1/*
2 Nuklear - 1.36.1 - public domain
3 no warrenty implied; use at your own risk.
4 authored from 2015-2017 by Micha Mettke
5
6ABOUT:
7 This is a minimal state graphical user interface single header toolkit
8 written in ANSI C and licensed under public domain.
9 It was designed as a simple embeddable user interface for application and does
10 not have any dependencies, a default renderbackend or OS window and input handling
11 but instead provides a very modular library approach by using simple input state
12 for input and draw commands describing primitive shapes as output.
13 So instead of providing a layered library that tries to abstract over a number
14 of platform and render backends it only focuses on the actual UI.
15
16VALUES:
17 - Graphical user interface toolkit
18 - Single header library
19 - Written in C89 (a.k.a. ANSI C or ISO C90)
20 - Small codebase (~17kLOC)
21 - Focus on portability, efficiency and simplicity
22 - No dependencies (not even the standard library if not wanted)
23 - Fully skinnable and customizable
24 - Low memory footprint with total memory control if needed or wanted
25 - UTF-8 support
26 - No global or hidden state
27 - Customizable library modules (you can compile and use only what you need)
28 - Optional font baker and vertex buffer output
29
30USAGE:
31 This library is self contained in one single header file and can be used either
32 in header only mode or in implementation mode. The header only mode is used
33 by default when included and allows including this header in other headers
34 and does not contain the actual implementation.
35
36 The implementation mode requires to define the preprocessor macro
37 NK_IMPLEMENTATION in *one* .c/.cpp file before #includeing this file, e.g.:
38
39 #define NK_IMPLEMENTATION
40 #include "nuklear.h"
41
42 Also optionally define the symbols listed in the section "OPTIONAL DEFINES"
43 below in header and implementation mode if you want to use additional functionality
44 or need more control over the library.
45 IMPORTANT: Every time you include "nuklear.h" you have to define the same flags.
46 This is very important not doing it either leads to compiler errors
47 or even worse stack corruptions.
48
49FEATURES:
50 - Absolutely no platform dependend code
51 - Memory management control ranging from/to
52 - Ease of use by allocating everything from standard library
53 - Control every byte of memory inside the library
54 - Font handling control ranging from/to
55 - Use your own font implementation for everything
56 - Use this libraries internal font baking and handling API
57 - Drawing output control ranging from/to
58 - Simple shapes for more high level APIs which already have drawing capabilities
59 - Hardware accessible anti-aliased vertex buffer output
60 - Customizable colors and properties ranging from/to
61 - Simple changes to color by filling a simple color table
62 - Complete control with ability to use skinning to decorate widgets
63 - Bendable UI library with widget ranging from/to
64 - Basic widgets like buttons, checkboxes, slider, ...
65 - Advanced widget like abstract comboboxes, contextual menus,...
66 - Compile time configuration to only compile what you need
67 - Subset which can be used if you do not want to link or use the standard library
68 - Can be easily modified to only update on user input instead of frame updates
69
70OPTIONAL DEFINES:
71 NK_PRIVATE
72 If defined declares all functions as static, so they can only be accessed
73 inside the file that contains the implementation
74
75 NK_INCLUDE_FIXED_TYPES
76 If defined it will include header <stdint.h> for fixed sized types
77 otherwise nuklear tries to select the correct type. If that fails it will
78 throw a compiler error and you have to select the correct types yourself.
79 <!> If used needs to be defined for implementation and header <!>
80
81 NK_INCLUDE_DEFAULT_ALLOCATOR
82 if defined it will include header <stdlib.h> and provide additional functions
83 to use this library without caring for memory allocation control and therefore
84 ease memory management.
85 <!> Adds the standard library with malloc and free so don't define if you
86 don't want to link to the standard library <!>
87 <!> If used needs to be defined for implementation and header <!>
88
89 NK_INCLUDE_STANDARD_IO
90 if defined it will include header <stdio.h> and provide
91 additional functions depending on file loading.
92 <!> Adds the standard library with fopen, fclose,... so don't define this
93 if you don't want to link to the standard library <!>
94 <!> If used needs to be defined for implementation and header <!>
95
96 NK_INCLUDE_STANDARD_VARARGS
97 if defined it will include header <stdarg.h> and provide
98 additional functions depending on variable arguments
99 <!> Adds the standard library with va_list and so don't define this if
100 you don't want to link to the standard library<!>
101 <!> If used needs to be defined for implementation and header <!>
102
103 NK_INCLUDE_VERTEX_BUFFER_OUTPUT
104 Defining this adds a vertex draw command list backend to this
105 library, which allows you to convert queue commands into vertex draw commands.
106 This is mainly if you need a hardware accessible format for OpenGL, DirectX,
107 Vulkan, Metal,...
108 <!> If used needs to be defined for implementation and header <!>
109
110 NK_INCLUDE_FONT_BAKING
111 Defining this adds the `stb_truetype` and `stb_rect_pack` implementation
112 to this library and provides font baking and rendering.
113 If you already have font handling or do not want to use this font handler
114 you don't have to define it.
115 <!> If used needs to be defined for implementation and header <!>
116
117 NK_INCLUDE_DEFAULT_FONT
118 Defining this adds the default font: ProggyClean.ttf into this library
119 which can be loaded into a font atlas and allows using this library without
120 having a truetype font
121 <!> Enabling this adds ~12kb to global stack memory <!>
122 <!> If used needs to be defined for implementation and header <!>
123
124 NK_INCLUDE_COMMAND_USERDATA
125 Defining this adds a userdata pointer into each command. Can be useful for
126 example if you want to provide custom shaders depending on the used widget.
127 Can be combined with the style structures.
128 <!> If used needs to be defined for implementation and header <!>
129
130 NK_BUTTON_TRIGGER_ON_RELEASE
131 Different platforms require button clicks occuring either on buttons being
132 pressed (up to down) or released (down to up).
133 By default this library will react on buttons being pressed, but if you
134 define this it will only trigger if a button is released.
135 <!> If used it is only required to be defined for the implementation part <!>
136
137 NK_ZERO_COMMAND_MEMORY
138 Defining this will zero out memory for each drawing command added to a
139 drawing queue (inside nk_command_buffer_push). Zeroing command memory
140 is very useful for fast checking (using memcmp) if command buffers are
141 equal and avoid drawing frames when nothing on screen has changed since
142 previous frame.
143
144 NK_ASSERT
145 If you don't define this, nuklear will use <assert.h> with assert().
146 <!> Adds the standard library so define to nothing of not wanted <!>
147 <!> If used needs to be defined for implementation and header <!>
148
149 NK_BUFFER_DEFAULT_INITIAL_SIZE
150 Initial buffer size allocated by all buffers while using the default allocator
151 functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't
152 want to allocate the default 4k memory then redefine it.
153 <!> If used needs to be defined for implementation and header <!>
154
155 NK_MAX_NUMBER_BUFFER
156 Maximum buffer size for the conversion buffer between float and string
157 Under normal circumstances this should be more than sufficient.
158 <!> If used needs to be defined for implementation and header <!>
159
160 NK_INPUT_MAX
161 Defines the max number of bytes which can be added as text input in one frame.
162 Under normal circumstances this should be more than sufficient.
163 <!> If used it is only required to be defined for the implementation part <!>
164
165 NK_MEMSET
166 You can define this to 'memset' or your own memset implementation
167 replacement. If not nuklear will use its own version.
168 <!> If used it is only required to be defined for the implementation part <!>
169
170 NK_MEMCPY
171 You can define this to 'memcpy' or your own memcpy implementation
172 replacement. If not nuklear will use its own version.
173 <!> If used it is only required to be defined for the implementation part <!>
174
175 NK_SQRT
176 You can define this to 'sqrt' or your own sqrt implementation
177 replacement. If not nuklear will use its own slow and not highly
178 accurate version.
179 <!> If used it is only required to be defined for the implementation part <!>
180
181 NK_SIN
182 You can define this to 'sinf' or your own sine implementation
183 replacement. If not nuklear will use its own approximation implementation.
184 <!> If used it is only required to be defined for the implementation part <!>
185
186 NK_COS
187 You can define this to 'cosf' or your own cosine implementation
188 replacement. If not nuklear will use its own approximation implementation.
189 <!> If used it is only required to be defined for the implementation part <!>
190
191 NK_STRTOD
192 You can define this to `strtod` or your own string to double conversion
193 implementation replacement. If not defined nuklear will use its own
194 imprecise and possibly unsafe version (does not handle nan or infinity!).
195 <!> If used it is only required to be defined for the implementation part <!>
196
197 NK_DTOA
198 You can define this to `dtoa` or your own double to string conversion
199 implementation replacement. If not defined nuklear will use its own
200 imprecise and possibly unsafe version (does not handle nan or infinity!).
201 <!> If used it is only required to be defined for the implementation part <!>
202
203 NK_VSNPRINTF
204 If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO`
205 and want to be safe define this to `vsnprintf` on compilers supporting
206 later versions of C or C++. By default nuklear will check for your stdlib version
207 in C as well as compiler version in C++. if `vsnprintf` is available
208 it will define it to `vsnprintf` directly. If not defined and if you have
209 older versions of C or C++ it will be defined to `vsprintf` which is unsafe.
210 <!> If used it is only required to be defined for the implementation part <!>
211
212 NK_BYTE
213 NK_INT16
214 NK_UINT16
215 NK_INT32
216 NK_UINT32
217 NK_SIZE_TYPE
218 NK_POINTER_TYPE
219 If you compile without NK_USE_FIXED_TYPE then a number of standard types
220 will be selected and compile time validated. If they are incorrect you can
221 define the correct types by overloading these type defines.
222
223CREDITS:
224 Developed by Micha Mettke and every direct or indirect contributor.
225
226 Embeds stb_texedit, stb_truetype and stb_rectpack by Sean Barret (public domain)
227 Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license).
228
229 Big thank you to Omar Cornut (ocornut@github) for his imgui library and
230 giving me the inspiration for this library, Casey Muratori for handmade hero
231 and his original immediate mode graphical user interface idea and Sean
232 Barret for his amazing single header libraries which restored my faith
233 in libraries and brought me to create some of my own.
234
235LICENSE:
236 This software is dual-licensed to the public domain and under the following
237 license: you are granted a perpetual, irrevocable license to copy, modify,
238 publish and distribute this file as you see fit.
239*/
240#ifndef NK_NUKLEAR_H_
241#define NK_NUKLEAR_H_
242
243#ifdef __cplusplus
244extern "C" {
245#endif
246/*
247 * ==============================================================
248 *
249 * CONSTANTS
250 *
251 * ===============================================================
252 */
253#define NK_UNDEFINED (-1.0f)
254#define NK_UTF_INVALID 0xFFFD /* internal invalid utf8 rune */
255#define NK_UTF_SIZE 4 /* describes the number of bytes a glyph consists of*/
256#ifndef NK_INPUT_MAX
257#define NK_INPUT_MAX 16
258#endif
259#ifndef NK_MAX_NUMBER_BUFFER
260#define NK_MAX_NUMBER_BUFFER 64
261#endif
262#ifndef NK_SCROLLBAR_HIDING_TIMEOUT
263#define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f
264#endif
265/*
266 * ==============================================================
267 *
268 * HELPER
269 *
270 * ===============================================================
271 */
272#ifndef NK_API
273 #ifdef NK_PRIVATE
274 #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L))
275 #define NK_API static inline
276 #elif defined(__cplusplus)
277 #define NK_API static inline
278 #else
279 #define NK_API static
280 #endif
281 #else
282 #define NK_API extern
283 #endif
284#endif
285
286#define NK_INTERN static
287#define NK_STORAGE static
288#define NK_GLOBAL static
289
290#define NK_FLAG(x) (1 << (x))
291#define NK_STRINGIFY(x) #x
292#define NK_MACRO_STRINGIFY(x) NK_STRINGIFY(x)
293#define NK_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2
294#define NK_STRING_JOIN_DELAY(arg1, arg2) NK_STRING_JOIN_IMMEDIATE(arg1, arg2)
295#define NK_STRING_JOIN(arg1, arg2) NK_STRING_JOIN_DELAY(arg1, arg2)
296
297#ifdef _MSC_VER
298#define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__COUNTER__)
299#else
300#define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__LINE__)
301#endif
302
303#ifndef NK_STATIC_ASSERT
304#define NK_STATIC_ASSERT(exp) typedef char NK_UNIQUE_NAME(_dummy_array)[(exp)?1:-1]
305#endif
306
307#ifndef NK_FILE_LINE
308#ifdef _MSC_VER
309#define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__COUNTER__)
310#else
311#define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__LINE__)
312#endif
313#endif
314
315#define NK_MIN(a,b) ((a) < (b) ? (a) : (b))
316#define NK_MAX(a,b) ((a) < (b) ? (b) : (a))
317#define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i))
318/*
319 * ===============================================================
320 *
321 * BASIC
322 *
323 * ===============================================================
324 */
325#ifdef NK_INCLUDE_FIXED_TYPES
326 #include <stdint.h>
327 #define NK_INT8 int8_t
328 #define NK_UINT8 uint8_t
329 #define NK_INT16 int16_t
330 #define NK_UINT16 uint16_t
331 #define NK_INT32 int32_t
332 #define NK_UINT32 uint32_t
333 #define NK_SIZE_TYPE uintptr_t
334 #define NK_POINTER_TYPE uintptr_t
335#else
336 #ifndef NK_INT8
337 #define NK_INT8 char
338 #endif
339 #ifndef NK_UINT8
340 #define NK_UINT8 unsigned char
341 #endif
342 #ifndef NK_INT16
343 #define NK_INT16 signed short
344 #endif
345 #ifndef NK_UINT16
346 #define NK_UINT16 unsigned short
347 #endif
348 #ifndef NK_INT32
349 #if defined(_MSC_VER)
350 #define NK_INT32 __int32
351 #else
352 #define NK_INT32 signed int
353 #endif
354 #endif
355 #ifndef NK_UINT32
356 #if defined(_MSC_VER)
357 #define NK_UINT32 unsigned __int32
358 #else
359 #define NK_UINT32 unsigned int
360 #endif
361 #endif
362 #ifndef NK_SIZE_TYPE
363 #if defined(_WIN64) && defined(_MSC_VER)
364 #define NK_SIZE_TYPE unsigned __int64
365 #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
366 #define NK_SIZE_TYPE unsigned __int32
367 #elif defined(__GNUC__) || defined(__clang__)
368 #if defined(__x86_64__) || defined(__ppc64__)
369 #define NK_SIZE_TYPE unsigned long
370 #else
371 #define NK_SIZE_TYPE unsigned int
372 #endif
373 #else
374 #define NK_SIZE_TYPE unsigned long
375 #endif
376 #endif
377 #ifndef NK_POINTER_TYPE
378 #if defined(_WIN64) && defined(_MSC_VER)
379 #define NK_POINTER_TYPE unsigned __int64
380 #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
381 #define NK_POINTER_TYPE unsigned __int32
382 #elif defined(__GNUC__) || defined(__clang__)
383 #if defined(__x86_64__) || defined(__ppc64__)
384 #define NK_POINTER_TYPE unsigned long
385 #else
386 #define NK_POINTER_TYPE unsigned int
387 #endif
388 #else
389 #define NK_POINTER_TYPE unsigned long
390 #endif
391 #endif
392#endif
393
394typedef NK_INT8 nk_char;
395typedef NK_UINT8 nk_uchar;
396typedef NK_UINT8 nk_byte;
397typedef NK_INT16 nk_short;
398typedef NK_UINT16 nk_ushort;
399typedef NK_INT32 nk_int;
400typedef NK_UINT32 nk_uint;
401typedef NK_SIZE_TYPE nk_size;
402typedef NK_POINTER_TYPE nk_ptr;
403
404typedef nk_uint nk_hash;
405typedef nk_uint nk_flags;
406typedef nk_uint nk_rune;
407
408/* Make sure correct type size:
409 * This will fire with a negative subscript error if the type sizes
410 * are set incorrectly by the compiler, and compile out if not */
411NK_STATIC_ASSERT(sizeof(nk_short) == 2);
412NK_STATIC_ASSERT(sizeof(nk_ushort) == 2);
413NK_STATIC_ASSERT(sizeof(nk_uint) == 4);
414NK_STATIC_ASSERT(sizeof(nk_int) == 4);
415NK_STATIC_ASSERT(sizeof(nk_byte) == 1);
416NK_STATIC_ASSERT(sizeof(nk_flags) >= 4);
417NK_STATIC_ASSERT(sizeof(nk_rune) >= 4);
418NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));
419NK_STATIC_ASSERT(sizeof(nk_ptr) >= sizeof(void*));
420
421/* ============================================================================
422 *
423 * API
424 *
425 * =========================================================================== */
426struct nk_buffer;
427struct nk_allocator;
428struct nk_command_buffer;
429struct nk_draw_command;
430struct nk_convert_config;
431struct nk_style_item;
432struct nk_text_edit;
433struct nk_draw_list;
434struct nk_user_font;
435struct nk_panel;
436struct nk_context;
437struct nk_draw_vertex_layout_element;
438struct nk_style_button;
439struct nk_style_toggle;
440struct nk_style_selectable;
441struct nk_style_slide;
442struct nk_style_progress;
443struct nk_style_scrollbar;
444struct nk_style_edit;
445struct nk_style_property;
446struct nk_style_chart;
447struct nk_style_combo;
448struct nk_style_tab;
449struct nk_style_window_header;
450struct nk_style_window;
451
452enum {nk_false, nk_true};
453struct nk_color {nk_byte r,g,b,a;};
454struct nk_colorf {float r,g,b,a;};
455struct nk_vec2 {float x,y;};
456struct nk_vec2i {short x, y;};
457struct nk_rect {float x,y,w,h;};
458struct nk_recti {short x,y,w,h;};
459typedef char nk_glyph[NK_UTF_SIZE];
460typedef union {void *ptr; int id;} nk_handle;
461struct nk_image {nk_handle handle;unsigned short w,h;unsigned short region[4];};
462struct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;};
463struct nk_scroll {nk_uint x, y;};
464
465enum nk_heading {NK_UP, NK_RIGHT, NK_DOWN, NK_LEFT};
466enum nk_button_behavior {NK_BUTTON_DEFAULT, NK_BUTTON_REPEATER};
467enum nk_modify {NK_FIXED = nk_false, NK_MODIFIABLE = nk_true};
468enum nk_orientation {NK_VERTICAL, NK_HORIZONTAL};
469enum nk_collapse_states {NK_MINIMIZED = nk_false, NK_MAXIMIZED = nk_true};
470enum nk_show_states {NK_HIDDEN = nk_false, NK_SHOWN = nk_true};
471enum nk_chart_type {NK_CHART_LINES, NK_CHART_COLUMN, NK_CHART_MAX};
472enum nk_chart_event {NK_CHART_HOVERING = 0x01, NK_CHART_CLICKED = 0x02};
473enum nk_color_format {NK_RGB, NK_RGBA};
474enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC};
475enum nk_layout_format {NK_DYNAMIC, NK_STATIC};
476enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB};
477
478typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size);
479typedef void (*nk_plugin_free)(nk_handle, void *old);
480typedef int(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode);
481typedef void(*nk_plugin_paste)(nk_handle, struct nk_text_edit*);
482typedef void(*nk_plugin_copy)(nk_handle, const char*, int len);
483
484struct nk_allocator {
485 nk_handle userdata;
486 nk_plugin_alloc alloc;
487 nk_plugin_free free;
488};
489enum nk_symbol_type {
490 NK_SYMBOL_NONE,
491 NK_SYMBOL_X,
492 NK_SYMBOL_UNDERSCORE,
493 NK_SYMBOL_CIRCLE_SOLID,
494 NK_SYMBOL_CIRCLE_OUTLINE,
495 NK_SYMBOL_RECT_SOLID,
496 NK_SYMBOL_RECT_OUTLINE,
497 NK_SYMBOL_TRIANGLE_UP,
498 NK_SYMBOL_TRIANGLE_DOWN,
499 NK_SYMBOL_TRIANGLE_LEFT,
500 NK_SYMBOL_TRIANGLE_RIGHT,
501 NK_SYMBOL_PLUS,
502 NK_SYMBOL_MINUS,
503 NK_SYMBOL_MAX
504};
505/* =============================================================================
506 *
507 * CONTEXT
508 *
509 * =============================================================================*/
510/* Contexts are the main entry point and the majestro of nuklear and contain all required state.
511 * They are used for window, memory, input, style, stack, commands and time management and need
512 * to be passed into all nuklear GUI specific functions.
513 *
514 * Usage
515 * -------------------
516 * To use a context it first has to be initialized which can be achieved by calling
517 * one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`.
518 * Each takes in a font handle and a specific way of handling memory. Memory control
519 * hereby ranges from standard library to just specifing a fixed sized block of memory
520 * which nuklear has to manage itself from.
521 *
522 * struct nk_context ctx;
523 * nk_init_xxx(&ctx, ...);
524 * while (1) {
525 * [...]
526 * nk_clear(&ctx);
527 * }
528 * nk_free(&ctx);
529 *
530 * Reference
531 * -------------------
532 * nk_init_default - Initializes context with standard library memory alloction (malloc,free)
533 * nk_init_fixed - Initializes context from single fixed size memory block
534 * nk_init - Initializes context with memory allocator callbacks for alloc and free
535 * nk_init_custom - Initializes context from two buffers. One for draw commands the other for window/panel/table allocations
536 * nk_clear - Called at the end of the frame to reset and prepare the context for the next frame
537 * nk_free - Shutdown and free all memory allocated inside the context
538 * nk_set_user_data - Utility function to pass user data to draw command
539 */
540#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
541/* nk_init_default - Initializes a `nk_context` struct with a default standard library allocator.
542 * Should be used if you don't want to be bothered with memory management in nuklear.
543 * Parameters:
544 * @ctx must point to an either stack or heap allocated `nk_context` struct
545 * @font must point to a previously initialized font handle for more info look at font documentation
546 * Return values:
547 * true(1) on success
548 * false(0) on failure */
549NK_API int nk_init_default(struct nk_context*, const struct nk_user_font*);
550#endif
551/* nk_init_fixed - Initializes a `nk_context` struct from a single fixed size memory block
552 * Should be used if you want complete control over nuklears memory management.
553 * Especially recommended for system with little memory or systems with virtual memory.
554 * For the later case you can just allocate for example 16MB of virtual memory
555 * and only the required amount of memory will actually be commited.
556 * IMPORTANT: make sure the passed memory block is aligned correctly for `nk_draw_commands`
557 * Parameters:
558 * @ctx must point to an either stack or heap allocated `nk_context` struct
559 * @memory must point to a previously allocated memory block
560 * @size must contain the total size of @memory
561 * @font must point to a previously initialized font handle for more info look at font documentation
562 * Return values:
563 * true(1) on success
564 * false(0) on failure */
565NK_API int nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*);
566/* nk_init - Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate
567 * memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation
568 * interface to nuklear. Can be useful for cases like monitoring memory consumption.
569 * Parameters:
570 * @ctx must point to an either stack or heap allocated `nk_context` struct
571 * @alloc must point to a previously allocated memory allocator
572 * @font must point to a previously initialized font handle for more info look at font documentation
573 * Return values:
574 * true(1) on success
575 * false(0) on failure */
576NK_API int nk_init(struct nk_context*, struct nk_allocator*, const struct nk_user_font*);
577/* nk_init_custom - Initializes a `nk_context` struct from two different either fixed or growing
578 * buffers. The first buffer is for allocating draw commands while the second buffer is
579 * used for allocating windows, panels and state tables.
580 * Parameters:
581 * @ctx must point to an either stack or heap allocated `nk_context` struct
582 * @cmds must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into
583 * @pool must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables
584 * @font must point to a previously initialized font handle for more info look at font documentation
585 * Return values:
586 * true(1) on success
587 * false(0) on failure */
588NK_API int nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*);
589/* nk_clear - Resets the context state at the end of the frame. This includes mostly
590 * garbage collector tasks like removing windows or table not called and therefore
591 * used anymore.
592 * Parameters:
593 * @ctx must point to a previously initialized `nk_context` struct */
594NK_API void nk_clear(struct nk_context*);
595/* nk_free - Frees all memory allocated by nuklear. Not needed if context was
596 * initialized with `nk_init_fixed`.
597 * Parameters:
598 * @ctx must point to a previously initialized `nk_context` struct */
599NK_API void nk_free(struct nk_context*);
600#ifdef NK_INCLUDE_COMMAND_USERDATA
601/* nk_set_user_data - Sets the currently passed userdata passed down into each draw command.
602 * Parameters:
603 * @ctx must point to a previously initialized `nk_context` struct
604 * @data handle with either pointer or index to be passed into every draw commands */
605NK_API void nk_set_user_data(struct nk_context*, nk_handle handle);
606#endif
607/* =============================================================================
608 *
609 * INPUT
610 *
611 * =============================================================================*/
612/* The input API is responsible for holding the current input state composed of
613 * mouse, key and text input states.
614 * It is worth noting that no direct os or window handling is done in nuklear.
615 * Instead all input state has to be provided by platform specific code. This in one hand
616 * expects more work from the user and complicates usage but on the other hand
617 * provides simple abstraction over a big number of platforms, libraries and other
618 * already provided functionality.
619 *
620 * Usage
621 * -------------------
622 * Input state needs to be provided to nuklear by first calling `nk_input_begin`
623 * which reset internal state like delta mouse position and button transistions.
624 * After `nk_input_begin` all current input state needs to be provided. This includes
625 * mouse motion, button and key pressed and released, text input and scrolling.
626 * Both event- or state-based input handling are supported by this API
627 * and should work without problems. Finally after all input state has been
628 * mirrored `nk_input_end` needs to be called to finish input process.
629 *
630 * struct nk_context ctx;
631 * nk_init_xxx(&ctx, ...);
632 * while (1) {
633 * Event evt;
634 * nk_input_begin(&ctx);
635 * while (GetEvent(&evt)) {
636 * if (evt.type == MOUSE_MOVE)
637 * nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
638 * else if (evt.type == ...) {
639 * ...
640 * }
641 * }
642 * nk_input_end(&ctx);
643 * [...]
644 * nk_clear(&ctx);
645 * }
646 * nk_free(&ctx);
647 *
648 * Reference
649 * -------------------
650 * nk_input_begin - Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls
651 * nk_input_motion - Mirrors mouse cursor position
652 * nk_input_key - Mirrors key state with either pressed or released
653 * nk_input_button - Mirrors mouse button state with either pressed or released
654 * nk_input_scroll - Mirrors mouse scroll values
655 * nk_input_char - Adds a single ASCII text character into an internal text buffer
656 * nk_input_glyph - Adds a single multi-byte UTF-8 character into an internal text buffer
657 * nk_input_unicode - Adds a single unicode rune into an internal text buffer
658 * nk_input_end - Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call
659 */
660enum nk_keys {
661 NK_KEY_NONE,
662 NK_KEY_SHIFT,
663 NK_KEY_CTRL,
664 NK_KEY_DEL,
665 NK_KEY_ENTER,
666 NK_KEY_TAB,
667 NK_KEY_BACKSPACE,
668 NK_KEY_COPY,
669 NK_KEY_CUT,
670 NK_KEY_PASTE,
671 NK_KEY_UP,
672 NK_KEY_DOWN,
673 NK_KEY_LEFT,
674 NK_KEY_RIGHT,
675 /* Shortcuts: text field */
676 NK_KEY_TEXT_INSERT_MODE,
677 NK_KEY_TEXT_REPLACE_MODE,
678 NK_KEY_TEXT_RESET_MODE,
679 NK_KEY_TEXT_LINE_START,
680 NK_KEY_TEXT_LINE_END,
681 NK_KEY_TEXT_START,
682 NK_KEY_TEXT_END,
683 NK_KEY_TEXT_UNDO,
684 NK_KEY_TEXT_REDO,
685 NK_KEY_TEXT_SELECT_ALL,
686 NK_KEY_TEXT_WORD_LEFT,
687 NK_KEY_TEXT_WORD_RIGHT,
688 /* Shortcuts: scrollbar */
689 NK_KEY_SCROLL_START,
690 NK_KEY_SCROLL_END,
691 NK_KEY_SCROLL_DOWN,
692 NK_KEY_SCROLL_UP,
693 NK_KEY_MAX
694};
695enum nk_buttons {
696 NK_BUTTON_LEFT,
697 NK_BUTTON_MIDDLE,
698 NK_BUTTON_RIGHT,
699 NK_BUTTON_MAX
700};
701/* nk_input_begin - Begins the input mirroring process by resetting text, scroll
702 * mouse previous mouse position and movement as well as key state transistions,
703 * Parameters:
704 * @ctx must point to an previously initialized `nk_context` struct */
705NK_API void nk_input_begin(struct nk_context*);
706/* nk_input_motion - Mirros current mouse position to nuklear
707 * Parameters:
708 * @ctx must point to an previously initialized `nk_context` struct
709 * @x must constain an integer describing the current mouse cursor x-position
710 * @y must constain an integer describing the current mouse cursor y-position */
711NK_API void nk_input_motion(struct nk_context*, int x, int y);
712/* nk_input_key - Mirros state of a specific key to nuklear
713 * Parameters:
714 * @ctx must point to an previously initialized `nk_context` struct
715 * @key must be any value specified in enum `nk_keys` that needs to be mirrored
716 * @down must be 0 for key is up and 1 for key is down */
717NK_API void nk_input_key(struct nk_context*, enum nk_keys, int down);
718/* nk_input_button - Mirros the state of a specific mouse button to nuklear
719 * Parameters:
720 * @ctx must point to an previously initialized `nk_context` struct
721 * @nk_buttons must be any value specified in enum `nk_buttons` that needs to be mirrored
722 * @x must constain an integer describing mouse cursor x-position on click up/down
723 * @y must constain an integer describing mouse cursor y-position on click up/down
724 * @down must be 0 for key is up and 1 for key is down */
725NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, int down);
726/* nk_input_char - Copies a single ASCII character into an internal text buffer
727 * This is basically a helper function to quickly push ASCII characters into
728 * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into
729 * struct `nk_input` between `nk_input_begin` and `nk_input_end`.
730 * Parameters:
731 * @ctx must point to an previously initialized `nk_context` struct
732 * @c must be a single ASCII character preferable one that can be printed */
733NK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val);
734/* nk_input_char - Copies a single ASCII character into an internal text buffer
735 * This is basically a helper function to quickly push ASCII characters into
736 * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into
737 * struct `nk_input` between `nk_input_begin` and `nk_input_end`.
738 * Parameters:
739 * @ctx must point to an previously initialized `nk_context` struct
740 * @c must be a single ASCII character preferable one that can be printed */
741NK_API void nk_input_char(struct nk_context*, char);
742/* nk_input_unicode - Converts a encoded unicode rune into UTF-8 and copies the result
743 * into an internal text buffer.
744 * Note that you can only push up to NK_INPUT_MAX bytes into
745 * struct `nk_input` between `nk_input_begin` and `nk_input_end`.
746 * Parameters:
747 * @ctx must point to an previously initialized `nk_context` struct
748 * @glyph UTF-32 uncode codepoint */
749NK_API void nk_input_glyph(struct nk_context*, const nk_glyph);
750/* nk_input_unicode - Converts a unicode rune into UTF-8 and copies the result
751 * into an internal text buffer.
752 * Note that you can only push up to NK_INPUT_MAX bytes into
753 * struct `nk_input` between `nk_input_begin` and `nk_input_end`.
754 * Parameters:
755 * @ctx must point to an previously initialized `nk_context` struct
756 * @glyph UTF-32 uncode codepoint */
757NK_API void nk_input_unicode(struct nk_context*, nk_rune);
758/* nk_input_end - End the input mirroring process by resetting mouse grabbing
759 * state to ensure the mouse cursor is not grabbed indefinitely.
760 * Parameters:
761 * @ctx must point to an previously initialized `nk_context` struct */
762NK_API void nk_input_end(struct nk_context*);
763/* =============================================================================
764 *
765 * DRAWING
766 *
767 * =============================================================================*/
768/* This library was designed to be render backend agnostic so it does
769 * not draw anything to screen directly. Instead all drawn shapes, widgets
770 * are made of, are buffered into memory and make up a command queue.
771 * Each frame therefore fills the command buffer with draw commands
772 * that then need to be executed by the user and his own render backend.
773 * After that the command buffer needs to be cleared and a new frame can be
774 * started. It is probably important to note that the command buffer is the main
775 * drawing API and the optional vertex buffer API only takes this format and
776 * converts it into a hardware accessible format.
777 *
778 * Usage
779 * -------------------
780 * To draw all draw commands accumulated over a frame you need your own render
781 * backend able to draw a number of 2D primitives. This includes at least
782 * filled and stroked rectangles, circles, text, lines, triangles and scissors.
783 * As soon as this criterion is met you can iterate over each draw command
784 * and execute each draw command in a interpreter like fashion:
785 *
786 * const struct nk_command *cmd = 0;
787 * nk_foreach(cmd, &ctx) {
788 * case NK_COMMAND_LINE:
789 * your_draw_line_function(...)
790 * break;
791 * case NK_COMMAND_RECT
792 * your_draw_rect_function(...)
793 * break;
794 * case ...:
795 * [...]
796 * }
797 *
798 * In program flow context draw commands need to be executed after input has been
799 * gathered and the complete UI with windows and their contained widgets have
800 * been executed and before calling `nk_clear` which frees all previously
801 * allocated draw commands.
802 *
803 * struct nk_context ctx;
804 * nk_init_xxx(&ctx, ...);
805 * while (1) {
806 * Event evt;
807 * nk_input_begin(&ctx);
808 * while (GetEvent(&evt)) {
809 * if (evt.type == MOUSE_MOVE)
810 * nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
811 * else if (evt.type == [...]) {
812 * [...]
813 * }
814 * }
815 * nk_input_end(&ctx);
816 *
817 * [...]
818 *
819 * const struct nk_command *cmd = 0;
820 * nk_foreach(cmd, &ctx) {
821 * case NK_COMMAND_LINE:
822 * your_draw_line_function(...)
823 * break;
824 * case NK_COMMAND_RECT
825 * your_draw_rect_function(...)
826 * break;
827 * case ...:
828 * [...]
829 * }
830 * nk_clear(&ctx);
831 * }
832 * nk_free(&ctx);
833 *
834 * While using draw commands makes sense for higher abstracted platforms like
835 * X11 and Win32 or drawing libraries it is often desirable to use graphics
836 * hardware directly. Therefore it is possible to just define
837 * `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output.
838 * To access the vertex output you first have to convert all draw commands into
839 * vertexes by calling `nk_convert` which takes in your prefered vertex format.
840 * After successfully converting all draw commands just iterate over and execute all
841 * vertex draw commands:
842 *
843 * struct nk_convert_config cfg = {};
844 * static const struct nk_draw_vertex_layout_element vertex_layout[] = {
845 * {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)},
846 * {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)},
847 * {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)},
848 * {NK_VERTEX_LAYOUT_END}
849 * };
850 * cfg.shape_AA = NK_ANTI_ALIASING_ON;
851 * cfg.line_AA = NK_ANTI_ALIASING_ON;
852 * cfg.vertex_layout = vertex_layout;
853 * cfg.vertex_size = sizeof(struct your_vertex);
854 * cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex);
855 * cfg.circle_segment_count = 22;
856 * cfg.curve_segment_count = 22;
857 * cfg.arc_segment_count = 22;
858 * cfg.global_alpha = 1.0f;
859 * cfg.null = dev->null;
860 *
861 * struct nk_buffer cmds, verts, idx;
862 * nk_buffer_init_default(&cmds);
863 * nk_buffer_init_default(&verts);
864 * nk_buffer_init_default(&idx);
865 * nk_convert(&ctx, &cmds, &verts, &idx, &cfg);
866 * nk_draw_foreach(cmd, &ctx, &cmds) {
867 * if (!cmd->elem_count) continue;
868 * [...]
869 * }
870 *
871 * Reference
872 * -------------------
873 * nk__begin - Returns the first draw command in the context draw command list to be drawn
874 * nk__next - Increments the draw command iterator to the next command inside the context draw command list
875 * nk_foreach - Iteratates over each draw command inside the context draw command list
876 *
877 * nk_convert - Converts from the abstract draw commands list into a hardware accessable vertex format
878 * nk__draw_begin - Returns the first vertex command in the context vertex draw list to be executed
879 * nk__draw_next - Increments the vertex command iterator to the next command inside the context vertex command list
880 * nk__draw_end - Returns the end of the vertex draw list
881 * nk_draw_foreach - Iterates over each vertex draw command inside the vertex draw list
882 */
883enum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON};
884enum nk_convert_result {
885 NK_CONVERT_SUCCESS = 0,
886 NK_CONVERT_INVALID_PARAM = 1,
887 NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1),
888 NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2),
889 NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3)
890};
891struct nk_draw_null_texture {
892 nk_handle texture;/* texture handle to a texture with a white pixel */
893 struct nk_vec2 uv; /* coordinates to a white pixel in the texture */
894};
895struct nk_convert_config {
896 float global_alpha; /* global alpha value */
897 enum nk_anti_aliasing line_AA; /* line anti-aliasing flag can be turned off if you are tight on memory */
898 enum nk_anti_aliasing shape_AA; /* shape anti-aliasing flag can be turned off if you are tight on memory */
899 unsigned int circle_segment_count; /* number of segments used for circles: default to 22 */
900 unsigned int arc_segment_count; /* number of segments used for arcs: default to 22 */
901 unsigned int curve_segment_count; /* number of segments used for curves: default to 22 */
902 struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */
903 const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */
904 nk_size vertex_size; /* sizeof one vertex for vertex packing */
905 nk_size vertex_alignment; /* vertex alignment: Can be optained by NK_ALIGNOF */
906};
907/* nk__begin - Returns a draw command list iterator to iterate all draw
908 * commands accumulated over one frame.
909 * Parameters:
910 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
911 * Return values:
912 * draw command pointer pointing to the first command inside the draw command list */
913NK_API const struct nk_command* nk__begin(struct nk_context*);
914/* nk__next - Returns a draw command list iterator to iterate all draw
915 * Parameters:
916 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
917 * @cmd must point to an previously a draw command either returned by `nk__begin` or `nk__next`
918 * Return values:
919 * draw command pointer pointing to the next command inside the draw command list */
920NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*);
921/* nk_foreach - Iterates over each draw command inside the context draw command list
922 * Parameters:
923 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
924 * @cmd pointer initialized to NULL */
925#define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c))
926#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
927/* nk_convert - converts all internal draw command into vertex draw commands and fills
928 * three buffers with vertexes, vertex draw commands and vertex indicies. The vertex format
929 * as well as some other configuration values have to be configurated by filling out a
930 * `nk_convert_config` struct.
931 * Parameters:
932 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
933 * @cmds must point to a previously initialized buffer to hold converted vertex draw commands
934 * @vertices must point to a previously initialized buffer to hold all produced verticies
935 * @elements must point to a previously initialized buffer to hold all procudes vertex indicies
936 * @config must point to a filled out `nk_config` struct to configure the conversion process
937 * Returns:
938 * returns NK_CONVERT_SUCCESS on success and a enum nk_convert_result error values if not */
939NK_API nk_flags nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*);
940/* nk__draw_begin - Returns a draw vertex command buffer iterator to iterate each the vertex draw command buffer
941 * Parameters:
942 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
943 * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer
944 * Return values:
945 * vertex draw command pointer pointing to the first command inside the vertex draw command buffer */
946NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*);
947/* nk__draw_end - Returns the vertex draw command at the end of the vertex draw command buffer
948 * Parameters:
949 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
950 * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer
951 * Return values:
952 * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */
953NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*);
954/* nk__draw_next - Increments the the vertex draw command buffer iterator
955 * Parameters:
956 * @cmd must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command
957 * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer
958 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
959 * Return values:
960 * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */
961NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*);
962/* nk_draw_foreach - Iterates over each vertex draw command inside a vertex draw command buffer
963 * Parameters:
964 * @cmd nk_draw_command pointer set to NULL
965 * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer
966 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame */
967#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx))
968#endif
969/* =============================================================================
970 *
971 * WINDOW
972 *
973 * =============================================================================
974 * Windows are the main persistent state used inside nuklear and are life time
975 * controlled by simply "retouching" (i.e. calling) each window each frame.
976 * All widgets inside nuklear can only be added inside function pair `nk_begin_xxx`
977 * and `nk_end`. Calling any widgets outside these two functions will result in an
978 * assert in debug or no state change in release mode.
979 *
980 * Each window holds frame persistent state like position, size, flags, state tables,
981 * and some garbage collected internal persistent widget state. Each window
982 * is linked into a window stack list which determines the drawing and overlapping
983 * order. The topmost window thereby is the currently active window.
984 *
985 * To change window position inside the stack occurs either automatically by
986 * user input by being clicked on or programatically by calling `nk_window_focus`.
987 * Windows by default are visible unless explicitly being defined with flag
988 * `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag
989 * `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling
990 * `nk_window_show`. To explicitly close and destroy a window call `nk_window_close`.
991 *
992 * Usage
993 * -------------------
994 * To create and keep a window you have to call one of the two `nk_begin_xxx`
995 * functions to start window declarations and `nk_end` at the end. Furthermore it
996 * is recommended to check the return value of `nk_begin_xxx` and only process
997 * widgets inside the window if the value is not 0. Either way you have to call
998 * `nk_end` at the end of window declarations. Furthmore do not attempt to
999 * nest `nk_begin_xxx` call which will hopefully result in an assert or if not
1000 * in a segmation fault.
1001 *
1002 * if (nk_begin_xxx(...) {
1003 * [... widgets ...]
1004 * }
1005 * nk_end(ctx);
1006 *
1007 * In the grand concept window and widget declarations need to occur after input
1008 * handling and before drawing to screen. Not doing so can results in higher
1009 * latency or at worst invalid behavior. Furthermore make sure that `nk_clear`
1010 * is called at the end of the frame. While nuklears default platform backends
1011 * already call `nk_clear` for you if you write your own backend not calling
1012 * `nk_clear` can cause asserts or even worse undefined behavior.
1013 *
1014 * struct nk_context ctx;
1015 * nk_init_xxx(&ctx, ...);
1016 * while (1) {
1017 * Event evt;
1018 * nk_input_begin(&ctx);
1019 * while (GetEvent(&evt)) {
1020 * if (evt.type == MOUSE_MOVE)
1021 * nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
1022 * else if (evt.type == [...]) {
1023 * nk_input_xxx(...);
1024 * }
1025 * }
1026 * nk_input_end(&ctx);
1027 *
1028 * if (nk_begin_xxx(...) {
1029 * [...]
1030 * }
1031 * nk_end(ctx);
1032 *
1033 * const struct nk_command *cmd = 0;
1034 * nk_foreach(cmd, &ctx) {
1035 * case NK_COMMAND_LINE:
1036 * your_draw_line_function(...)
1037 * break;
1038 * case NK_COMMAND_RECT
1039 * your_draw_rect_function(...)
1040 * break;
1041 * case ...:
1042 * [...]
1043 * }
1044 * nk_clear(&ctx);
1045 * }
1046 * nk_free(&ctx);
1047 *
1048 * Reference
1049 * -------------------
1050 * nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed
1051 * nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title
1052 * nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup
1053 *
1054 * nk_window_find - finds and returns the window with give name
1055 * nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window.
1056 * nk_window_get_position - returns the position of the currently processed window
1057 * nk_window_get_size - returns the size with width and height of the currently processed window
1058 * nk_window_get_width - returns the width of the currently processed window
1059 * nk_window_get_height - returns the height of the currently processed window
1060 * nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window
1061 * nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window
1062 * nk_window_get_content_region_min - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window
1063 * nk_window_get_content_region_max - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window
1064 * nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window
1065 * nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets
1066 *
1067 * nk_window_has_focus - returns if the currently processed window is currently active
1068 * nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed
1069 * nk_window_is_closed - returns if the currently processed window was closed
1070 * nk_window_is_hidden - returns if the currently processed window was hidden
1071 * nk_window_is_active - same as nk_window_has_focus for some reason
1072 * nk_window_is_hovered - returns if the currently processed window is currently being hovered by mouse
1073 * nk_window_is_any_hovered - return if any wndow currently hovered
1074 * nk_item_is_any_active - returns if any window or widgets is currently hovered or active
1075 *
1076 * nk_window_set_bounds - updates position and size of the currently processed window
1077 * nk_window_set_position - updates position of the currently process window
1078 * nk_window_set_size - updates the size of the currently processed window
1079 * nk_window_set_focus - set the currently processed window as active window
1080 *
1081 * nk_window_close - closes the window with given window name which deletes the window at the end of the frame
1082 * nk_window_collapse - collapses the window with given window name
1083 * nk_window_collapse_if - collapses the window with given window name if the given condition was met
1084 * nk_window_show - hides a visible or reshows a hidden window
1085 * nk_window_show_if - hides/shows a window depending on condition
1086 */
1087enum nk_panel_flags {
1088 NK_WINDOW_BORDER = NK_FLAG(0), /* Draws a border around the window to visually separate the window from the background */
1089 NK_WINDOW_MOVABLE = NK_FLAG(1), /* The movable flag indicates that a window can be moved by user input or by dragging the window header */
1090 NK_WINDOW_SCALABLE = NK_FLAG(2), /* The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window */
1091 NK_WINDOW_CLOSABLE = NK_FLAG(3), /* adds a closable icon into the header */
1092 NK_WINDOW_MINIMIZABLE = NK_FLAG(4), /* adds a minimize icon into the header */
1093 NK_WINDOW_NO_SCROLLBAR = NK_FLAG(5), /* Removes the scrollbar from the window */
1094 NK_WINDOW_TITLE = NK_FLAG(6), /* Forces a header at the top at the window showing the title */
1095 NK_WINDOW_SCROLL_AUTO_HIDE = NK_FLAG(7), /* Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame */
1096 NK_WINDOW_BACKGROUND = NK_FLAG(8), /* Always keep window in the background */
1097 NK_WINDOW_SCALE_LEFT = NK_FLAG(9), /* Puts window scaler in the left-ottom corner instead right-bottom*/
1098 NK_WINDOW_NO_INPUT = NK_FLAG(10) /* Prevents window of scaling, moving or getting focus */
1099};
1100/* nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed
1101 * Parameters:
1102 * @ctx must point to an previously initialized `nk_context` struct
1103 * @title window title and identifier. Needs to be persitent over frames to identify the window
1104 * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame
1105 * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors
1106 * Return values:
1107 * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise for example if minimized `*/
1108NK_API int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);
1109/* nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title
1110 * Parameters:
1111 * @ctx must point to an previously initialized `nk_context` struct
1112 * @name window identifier. Needs to be persitent over frames to identify the window
1113 * @title window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set
1114 * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame
1115 * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors
1116 * Return values:
1117 * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise `*/
1118NK_API int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);
1119/* nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup.
1120 * All widget calls after this functions will result in asserts or no state changes
1121 * Parameters:
1122 * @ctx must point to an previously initialized `nk_context` struct */
1123NK_API void nk_end(struct nk_context *ctx);
1124/* nk_window_find - finds and returns the window with give name
1125 * Parameters:
1126 * @ctx must point to an previously initialized `nk_context` struct
1127 * @name window identifier
1128 * Return values:
1129 * returns a `nk_window` struct pointing to the idified window or 0 if no window with given name was found */
1130NK_API struct nk_window *nk_window_find(struct nk_context *ctx, const char *name);
1131/* nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window.
1132 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1133 * Parameters:
1134 * @ctx must point to an previously initialized `nk_context` struct
1135 * Return values:
1136 * returns a `nk_rect` struct with window upper left position and size */
1137NK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx);
1138/* nk_window_get_position - returns the position of the currently processed window.
1139 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1140 * Parameters:
1141 * @ctx must point to an previously initialized `nk_context` struct
1142 * Return values:
1143 * returns a `nk_vec2` struct with window upper left position */
1144NK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx);
1145/* nk_window_get_size - returns the size with width and height of the currently processed window.
1146 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1147 * Parameters:
1148 * @ctx must point to an previously initialized `nk_context` struct
1149 * Return values:
1150 * returns a `nk_vec2` struct with window size */
1151NK_API struct nk_vec2 nk_window_get_size(const struct nk_context*);
1152/* nk_window_get_width - returns the width of the currently processed window.
1153 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1154 * Parameters:
1155 * @ctx must point to an previously initialized `nk_context` struct
1156 * Return values:
1157 * returns the window width */
1158NK_API float nk_window_get_width(const struct nk_context*);
1159/* nk_window_get_height - returns the height of the currently processed window.
1160 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1161 * Parameters:
1162 * @ctx must point to an previously initialized `nk_context` struct
1163 * Return values:
1164 * returns the window height */
1165NK_API float nk_window_get_height(const struct nk_context*);
1166/* nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window.
1167 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1168 * Parameters:
1169 * @ctx must point to an previously initialized `nk_context` struct
1170 * Return values:
1171 * returns a pointer to window internal `nk_panel` state. DO NOT keep this pointer around it is only valid until `nk_end` */
1172NK_API struct nk_panel* nk_window_get_panel(struct nk_context*);
1173/* nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window.
1174 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1175 * Parameters:
1176 * @ctx must point to an previously initialized `nk_context` struct
1177 * Return values:
1178 * returns `nk_rect` struct with screen position and size (no scrollbar offset) of the visible space inside the current window */
1179NK_API struct nk_rect nk_window_get_content_region(struct nk_context*);
1180/* nk_window_get_content_region_min - returns the upper left position of the currently visible and non-clipped space inside the currently processed window.
1181 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1182 * Parameters:
1183 * @ctx must point to an previously initialized `nk_context` struct
1184 * Return values:
1185 * returns `nk_vec2` struct with upper left screen position (no scrollbar offset) of the visible space inside the current window */
1186NK_API struct nk_vec2 nk_window_get_content_region_min(struct nk_context*);
1187/* nk_window_get_content_region_max - returns the lower right screen position of the currently visible and non-clipped space inside the currently processed window.
1188 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1189 * Parameters:
1190 * @ctx must point to an previously initialized `nk_context` struct
1191 * Return values:
1192 * returns `nk_vec2` struct with lower right screen position (no scrollbar offset) of the visible space inside the current window */
1193NK_API struct nk_vec2 nk_window_get_content_region_max(struct nk_context*);
1194/* nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window
1195 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1196 * Parameters:
1197 * @ctx must point to an previously initialized `nk_context` struct
1198 * Return values:
1199 * returns `nk_vec2` struct with size the visible space inside the current window */
1200NK_API struct nk_vec2 nk_window_get_content_region_size(struct nk_context*);
1201/* nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets
1202 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1203 * Parameters:
1204 * @ctx must point to an previously initialized `nk_context` struct
1205 * Return values:
1206 * returns a pointer to window internal `nk_command_buffer` struct used as drawing canvas. Can be used to do custom drawing */
1207NK_API struct nk_command_buffer* nk_window_get_canvas(struct nk_context*);
1208/* nk_window_has_focus - returns if the currently processed window is currently active
1209 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1210 * Parameters:
1211 * @ctx must point to an previously initialized `nk_context` struct
1212 * Return values:
1213 * returns 0 if current window is not active or 1 if it is */
1214NK_API int nk_window_has_focus(const struct nk_context*);
1215/* nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed
1216 * Parameters:
1217 * @ctx must point to an previously initialized `nk_context` struct
1218 * @name of window you want to check is collapsed
1219 * Return values:
1220 * returns 1 if current window is minimized and 0 if window not found or is not minimized */
1221NK_API int nk_window_is_collapsed(struct nk_context *ctx, const char *name);
1222/* nk_window_is_closed - returns if the window with given name was closed by calling `nk_close`
1223 * Parameters:
1224 * @ctx must point to an previously initialized `nk_context` struct
1225 * @name of window you want to check is closed
1226 * Return values:
1227 * returns 1 if current window was closed or 0 window not found or not closed */
1228NK_API int nk_window_is_closed(struct nk_context*, const char*);
1229/* nk_window_is_hidden - returns if the window with given name is hidden
1230 * Parameters:
1231 * @ctx must point to an previously initialized `nk_context` struct
1232 * @name of window you want to check is hidden
1233 * Return values:
1234 * returns 1 if current window is hidden or 0 window not found or visible */
1235NK_API int nk_window_is_hidden(struct nk_context*, const char*);
1236/* nk_window_is_active - same as nk_window_has_focus for some reason
1237 * Parameters:
1238 * @ctx must point to an previously initialized `nk_context` struct
1239 * @name of window you want to check is hidden
1240 * Return values:
1241 * returns 1 if current window is active or 0 window not found or not active */
1242NK_API int nk_window_is_active(struct nk_context*, const char*);
1243/* nk_window_is_hovered - return if the current window is being hovered
1244 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1245 * Parameters:
1246 * @ctx must point to an previously initialized `nk_context` struct
1247 * Return values:
1248 * returns 1 if current window is hovered or 0 otherwise */
1249NK_API int nk_window_is_hovered(struct nk_context*);
1250/* nk_window_is_any_hovered - returns if the any window is being hovered
1251 * Parameters:
1252 * @ctx must point to an previously initialized `nk_context` struct
1253 * Return values:
1254 * returns 1 if any window is hovered or 0 otherwise */
1255NK_API int nk_window_is_any_hovered(struct nk_context*);
1256/* nk_item_is_any_active - returns if the any window is being hovered or any widget is currently active.
1257 * Can be used to decide if input should be processed by UI or your specific input handling.
1258 * Example could be UI and 3D camera to move inside a 3D space.
1259 * Parameters:
1260 * @ctx must point to an previously initialized `nk_context` struct
1261 * Return values:
1262 * returns 1 if any window is hovered or any item is active or 0 otherwise */
1263NK_API int nk_item_is_any_active(struct nk_context*);
1264/* nk_window_set_bounds - updates position and size of the currently processed window
1265 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1266 * Parameters:
1267 * @ctx must point to an previously initialized `nk_context` struct
1268 * @bounds points to a `nk_rect` struct with the new position and size of currently active window */
1269NK_API void nk_window_set_bounds(struct nk_context*, struct nk_rect bounds);
1270/* nk_window_set_position - updates position of the currently processed window
1271 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1272 * Parameters:
1273 * @ctx must point to an previously initialized `nk_context` struct
1274 * @pos points to a `nk_vec2` struct with the new position of currently active window */
1275NK_API void nk_window_set_position(struct nk_context*, struct nk_vec2 pos);
1276/* nk_window_set_size - updates size of the currently processed window
1277 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1278 * Parameters:
1279 * @ctx must point to an previously initialized `nk_context` struct
1280 * @bounds points to a `nk_vec2` struct with the new size of currently active window */
1281NK_API void nk_window_set_size(struct nk_context*, struct nk_vec2);
1282/* nk_window_set_focus - sets the window with given name as active
1283 * Parameters:
1284 * @ctx must point to an previously initialized `nk_context` struct
1285 * @name of the window to be set active */
1286NK_API void nk_window_set_focus(struct nk_context*, const char *name);
1287/* nk_window_close - closed a window and marks it for being freed at the end of the frame
1288 * Parameters:
1289 * @ctx must point to an previously initialized `nk_context` struct
1290 * @name of the window to be closed */
1291NK_API void nk_window_close(struct nk_context *ctx, const char *name);
1292/* nk_window_collapse - updates collapse state of a window with given name
1293 * Parameters:
1294 * @ctx must point to an previously initialized `nk_context` struct
1295 * @name of the window to be either collapse or maximize */
1296NK_API void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state);
1297/* nk_window_collapse - updates collapse state of a window with given name if given condition is met
1298 * Parameters:
1299 * @ctx must point to an previously initialized `nk_context` struct
1300 * @name of the window to be either collapse or maximize
1301 * @state the window should be put into
1302 * @condition that has to be true to actually commit the collsage state change */
1303NK_API void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond);
1304/* nk_window_show - updates visibility state of a window with given name
1305 * Parameters:
1306 * @ctx must point to an previously initialized `nk_context` struct
1307 * @name of the window to be either collapse or maximize
1308 * @state with either visible or hidden to modify the window with */
1309NK_API void nk_window_show(struct nk_context*, const char *name, enum nk_show_states);
1310/* nk_window_show_if - updates visibility state of a window with given name if a given condition is met
1311 * Parameters:
1312 * @ctx must point to an previously initialized `nk_context` struct
1313 * @name of the window to be either collapse or maximize
1314 * @state with either visible or hidden to modify the window with
1315 * @condition that has to be true to actually commit the visible state change */
1316NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond);
1317/* =============================================================================
1318 *
1319 * LAYOUT
1320 *
1321 * ============================================================================= */
1322NK_API void nk_layout_row_dynamic(struct nk_context*, float height, int cols);
1323NK_API void nk_layout_row_static(struct nk_context*, float height, int item_width, int cols);
1324
1325NK_API void nk_layout_row_begin(struct nk_context*, enum nk_layout_format, float row_height, int cols);
1326NK_API void nk_layout_row_push(struct nk_context*, float value);
1327NK_API void nk_layout_row_end(struct nk_context*);
1328NK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio);
1329
1330NK_API void nk_layout_row_template_begin(struct nk_context*, float height);
1331NK_API void nk_layout_row_template_push_dynamic(struct nk_context*);
1332NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width);
1333NK_API void nk_layout_row_template_push_static(struct nk_context*, float width);
1334NK_API void nk_layout_row_template_end(struct nk_context*);
1335
1336NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count);
1337NK_API void nk_layout_space_push(struct nk_context*, struct nk_rect);
1338NK_API void nk_layout_space_end(struct nk_context*);
1339
1340NK_API struct nk_rect nk_layout_space_bounds(struct nk_context*);
1341NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2);
1342NK_API struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2);
1343NK_API struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect);
1344NK_API struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect);
1345NK_API float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width);
1346/* =============================================================================
1347 *
1348 * GROUP
1349 *
1350 * ============================================================================= */
1351NK_API int nk_group_begin(struct nk_context*, const char *title, nk_flags);
1352NK_API int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char*, nk_flags);
1353NK_API int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll*, const char *title, nk_flags);
1354NK_API void nk_group_scrolled_end(struct nk_context*);
1355NK_API void nk_group_end(struct nk_context*);
1356/* =============================================================================
1357 *
1358 * LIST VIEW
1359 *
1360 * ============================================================================= */
1361struct nk_list_view {
1362/* public: */
1363 int begin, end, count;
1364/* private: */
1365 int total_height;
1366 struct nk_context *ctx;
1367 nk_uint *scroll_pointer;
1368 nk_uint scroll_value;
1369};
1370NK_API int nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count);
1371NK_API void nk_list_view_end(struct nk_list_view*);
1372/* =============================================================================
1373 *
1374 * TREE
1375 *
1376 * ============================================================================= */
1377#define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)
1378#define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)
1379NK_API int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
1380#define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)
1381#define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)
1382NK_API int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
1383NK_API void nk_tree_pop(struct nk_context*);
1384NK_API int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);
1385NK_API int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);
1386NK_API void nk_tree_state_pop(struct nk_context*);
1387/* =============================================================================
1388 *
1389 * WIDGET
1390 *
1391 * ============================================================================= */
1392enum nk_widget_layout_states {
1393 NK_WIDGET_INVALID, /* The widget cannot be seen and is completely out of view */
1394 NK_WIDGET_VALID, /* The widget is completely inside the window and can be updated and drawn */
1395 NK_WIDGET_ROM /* The widget is partially visible and cannot be updated */
1396};
1397enum nk_widget_states {
1398 NK_WIDGET_STATE_MODIFIED = NK_FLAG(1),
1399 NK_WIDGET_STATE_INACTIVE = NK_FLAG(2), /* widget is neither active nor hovered */
1400 NK_WIDGET_STATE_ENTERED = NK_FLAG(3), /* widget has been hovered on the current frame */
1401 NK_WIDGET_STATE_HOVER = NK_FLAG(4), /* widget is being hovered */
1402 NK_WIDGET_STATE_ACTIVED = NK_FLAG(5),/* widget is currently activated */
1403 NK_WIDGET_STATE_LEFT = NK_FLAG(6), /* widget is from this frame on not hovered anymore */
1404 NK_WIDGET_STATE_HOVERED = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /* widget is being hovered */
1405 NK_WIDGET_STATE_ACTIVE = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /* widget is currently activated */
1406};
1407NK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*);
1408NK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, struct nk_context*, struct nk_vec2);
1409NK_API struct nk_rect nk_widget_bounds(struct nk_context*);
1410NK_API struct nk_vec2 nk_widget_position(struct nk_context*);
1411NK_API struct nk_vec2 nk_widget_size(struct nk_context*);
1412NK_API float nk_widget_width(struct nk_context*);
1413NK_API float nk_widget_height(struct nk_context*);
1414NK_API int nk_widget_is_hovered(struct nk_context*);
1415NK_API int nk_widget_is_mouse_clicked(struct nk_context*, enum nk_buttons);
1416NK_API int nk_widget_has_mouse_click_down(struct nk_context*, enum nk_buttons, int down);
1417NK_API void nk_spacing(struct nk_context*, int cols);
1418/* =============================================================================
1419 *
1420 * TEXT
1421 *
1422 * ============================================================================= */
1423enum nk_text_align {
1424 NK_TEXT_ALIGN_LEFT = 0x01,
1425 NK_TEXT_ALIGN_CENTERED = 0x02,
1426 NK_TEXT_ALIGN_RIGHT = 0x04,
1427 NK_TEXT_ALIGN_TOP = 0x08,
1428 NK_TEXT_ALIGN_MIDDLE = 0x10,
1429 NK_TEXT_ALIGN_BOTTOM = 0x20
1430};
1431enum nk_text_alignment {
1432 NK_TEXT_LEFT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT,
1433 NK_TEXT_CENTERED = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED,
1434 NK_TEXT_RIGHT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT
1435};
1436NK_API void nk_text(struct nk_context*, const char*, int, nk_flags);
1437NK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color);
1438NK_API void nk_text_wrap(struct nk_context*, const char*, int);
1439NK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color);
1440NK_API void nk_label(struct nk_context*, const char*, nk_flags align);
1441NK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color);
1442NK_API void nk_label_wrap(struct nk_context*, const char*);
1443NK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color);
1444NK_API void nk_image(struct nk_context*, struct nk_image);
1445#ifdef NK_INCLUDE_STANDARD_VARARGS
1446NK_API void nk_labelf(struct nk_context*, nk_flags, const char*, ...);
1447NK_API void nk_labelf_colored(struct nk_context*, nk_flags align, struct nk_color, const char*,...);
1448NK_API void nk_labelf_wrap(struct nk_context*, const char*,...);
1449NK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, const char*,...);
1450NK_API void nk_value_bool(struct nk_context*, const char *prefix, int);
1451NK_API void nk_value_int(struct nk_context*, const char *prefix, int);
1452NK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int);
1453NK_API void nk_value_float(struct nk_context*, const char *prefix, float);
1454NK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color);
1455NK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color);
1456NK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color);
1457#endif
1458/* =============================================================================
1459 *
1460 * BUTTON
1461 *
1462 * ============================================================================= */
1463NK_API int nk_button_text(struct nk_context*, const char *title, int len);
1464NK_API int nk_button_label(struct nk_context*, const char *title);
1465NK_API int nk_button_color(struct nk_context*, struct nk_color);
1466NK_API int nk_button_symbol(struct nk_context*, enum nk_symbol_type);
1467NK_API int nk_button_image(struct nk_context*, struct nk_image img);
1468NK_API int nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment);
1469NK_API int nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
1470NK_API int nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment);
1471NK_API int nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment);
1472NK_API int nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len);
1473NK_API int nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title);
1474NK_API int nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type);
1475NK_API int nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img);
1476NK_API int k_button_symbol_label_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, nk_flags text_alignment);
1477NK_API int nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment);
1478NK_API int nk_button_symbol_label_styled(struct nk_context *ctx, const struct nk_style_button *style, enum nk_symbol_type symbol, const char *title, nk_flags align);
1479NK_API int nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment);
1480NK_API int nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment);
1481NK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior);
1482NK_API int nk_button_push_behavior(struct nk_context*, enum nk_button_behavior);
1483NK_API int nk_button_pop_behavior(struct nk_context*);
1484/* =============================================================================
1485 *
1486 * CHECKBOX
1487 *
1488 * ============================================================================= */
1489NK_API int nk_check_label(struct nk_context*, const char*, int active);
1490NK_API int nk_check_text(struct nk_context*, const char*, int,int active);
1491NK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value);
1492NK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value);
1493NK_API int nk_checkbox_label(struct nk_context*, const char*, int *active);
1494NK_API int nk_checkbox_text(struct nk_context*, const char*, int, int *active);
1495NK_API int nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value);
1496NK_API int nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value);
1497/* =============================================================================
1498 *
1499 * RADIO BUTTON
1500 *
1501 * ============================================================================= */
1502NK_API int nk_radio_label(struct nk_context*, const char*, int *active);
1503NK_API int nk_radio_text(struct nk_context*, const char*, int, int *active);
1504NK_API int nk_option_label(struct nk_context*, const char*, int active);
1505NK_API int nk_option_text(struct nk_context*, const char*, int, int active);
1506/* =============================================================================
1507 *
1508 * SELECTABLE
1509 *
1510 * ============================================================================= */
1511NK_API int nk_selectable_label(struct nk_context*, const char*, nk_flags align, int *value);
1512NK_API int nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, int *value);
1513NK_API int nk_selectable_image_label(struct nk_context*,struct nk_image, const char*, nk_flags align, int *value);
1514NK_API int nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, int *value);
1515NK_API int nk_select_label(struct nk_context*, const char*, nk_flags align, int value);
1516NK_API int nk_select_text(struct nk_context*, const char*, int, nk_flags align, int value);
1517NK_API int nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, int value);
1518NK_API int nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, int value);
1519/* =============================================================================
1520 *
1521 * SLIDER
1522 *
1523 * ============================================================================= */
1524NK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step);
1525NK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step);
1526NK_API int nk_slider_float(struct nk_context*, float min, float *val, float max, float step);
1527NK_API int nk_slider_int(struct nk_context*, int min, int *val, int max, int step);
1528/* =============================================================================
1529 *
1530 * PROGRESSBAR
1531 *
1532 * ============================================================================= */
1533NK_API int nk_progress(struct nk_context*, nk_size *cur, nk_size max, int modifyable);
1534NK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, int modifyable);
1535
1536/* =============================================================================
1537 *
1538 * COLOR PICKER
1539 *
1540 * ============================================================================= */
1541NK_API struct nk_color nk_color_picker(struct nk_context*, struct nk_color, enum nk_color_format);
1542NK_API int nk_color_pick(struct nk_context*, struct nk_color*, enum nk_color_format);
1543/* =============================================================================
1544 *
1545 * PROPERTIES
1546 *
1547 * ============================================================================= */
1548NK_API void nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel);
1549NK_API void nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel);
1550NK_API void nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel);
1551NK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel);
1552NK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel);
1553NK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel);
1554/* =============================================================================
1555 *
1556 * TEXT EDIT
1557 *
1558 * ============================================================================= */
1559enum nk_edit_flags {
1560 NK_EDIT_DEFAULT = 0,
1561 NK_EDIT_READ_ONLY = NK_FLAG(0),
1562 NK_EDIT_AUTO_SELECT = NK_FLAG(1),
1563 NK_EDIT_SIG_ENTER = NK_FLAG(2),
1564 NK_EDIT_ALLOW_TAB = NK_FLAG(3),
1565 NK_EDIT_NO_CURSOR = NK_FLAG(4),
1566 NK_EDIT_SELECTABLE = NK_FLAG(5),
1567 NK_EDIT_CLIPBOARD = NK_FLAG(6),
1568 NK_EDIT_CTRL_ENTER_NEWLINE = NK_FLAG(7),
1569 NK_EDIT_NO_HORIZONTAL_SCROLL = NK_FLAG(8),
1570 NK_EDIT_ALWAYS_INSERT_MODE = NK_FLAG(9),
1571 NK_EDIT_MULTILINE = NK_FLAG(10),
1572 NK_EDIT_GOTO_END_ON_ACTIVATE = NK_FLAG(11)
1573};
1574enum nk_edit_types {
1575 NK_EDIT_SIMPLE = NK_EDIT_ALWAYS_INSERT_MODE,
1576 NK_EDIT_FIELD = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD,
1577 NK_EDIT_BOX = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD,
1578 NK_EDIT_EDITOR = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD
1579};
1580enum nk_edit_events {
1581 NK_EDIT_ACTIVE = NK_FLAG(0), /* edit widget is currently being modified */
1582 NK_EDIT_INACTIVE = NK_FLAG(1), /* edit widget is not active and is not being modified */
1583 NK_EDIT_ACTIVATED = NK_FLAG(2), /* edit widget went from state inactive to state active */
1584 NK_EDIT_DEACTIVATED = NK_FLAG(3), /* edit widget went from state active to state inactive */
1585 NK_EDIT_COMMITED = NK_FLAG(4) /* edit widget has received an enter and lost focus */
1586};
1587NK_API void nk_edit_focus(struct nk_context*, nk_flags flags);
1588NK_API void nk_edit_unfocus(struct nk_context*);
1589NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter);
1590NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter);
1591NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter);
1592/* =============================================================================
1593 *
1594 * CHART
1595 *
1596 * ============================================================================= */
1597NK_API int nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max);
1598NK_API int nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max);
1599NK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value);
1600NK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value);
1601NK_API nk_flags nk_chart_push(struct nk_context*, float);
1602NK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int);
1603NK_API void nk_chart_end(struct nk_context*);
1604NK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset);
1605NK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset);
1606/* =============================================================================
1607 *
1608 * POPUP
1609 *
1610 * ============================================================================= */
1611NK_API int nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds);
1612NK_API void nk_popup_close(struct nk_context*);
1613NK_API void nk_popup_end(struct nk_context*);
1614/* =============================================================================
1615 *
1616 * COMBOBOX
1617 *
1618 * ============================================================================= */
1619NK_API int nk_combo(struct nk_context*, const char **items, int count, int selected, int item_height, struct nk_vec2 size);
1620NK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size);
1621NK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size);
1622NK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size);
1623NK_API void nk_combobox(struct nk_context*, const char **items, int count, int *selected, int item_height, struct nk_vec2 size);
1624NK_API void nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size);
1625NK_API void nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator,int *selected, int count, int item_height, struct nk_vec2 size);
1626NK_API void nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size);
1627/* =============================================================================
1628 *
1629 * ABSTRACT COMBOBOX
1630 *
1631 * ============================================================================= */
1632NK_API int nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size);
1633NK_API int nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size);
1634NK_API int nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size);
1635NK_API int nk_combo_begin_symbol(struct nk_context*, enum nk_symbol_type, struct nk_vec2 size);
1636NK_API int nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size);
1637NK_API int nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size);
1638NK_API int nk_combo_begin_image(struct nk_context*, struct nk_image img, struct nk_vec2 size);
1639NK_API int nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size);
1640NK_API int nk_combo_begin_image_text(struct nk_context*, const char *selected, int, struct nk_image, struct nk_vec2 size);
1641NK_API int nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment);
1642NK_API int nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment);
1643NK_API int nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);
1644NK_API int nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment);
1645NK_API int nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);
1646NK_API int nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
1647NK_API void nk_combo_close(struct nk_context*);
1648NK_API void nk_combo_end(struct nk_context*);
1649/* =============================================================================
1650 *
1651 * CONTEXTUAL
1652 *
1653 * ============================================================================= */
1654NK_API int nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds);
1655NK_API int nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align);
1656NK_API int nk_contextual_item_label(struct nk_context*, const char*, nk_flags align);
1657NK_API int nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);
1658NK_API int nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);
1659NK_API int nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);
1660NK_API int nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
1661NK_API void nk_contextual_close(struct nk_context*);
1662NK_API void nk_contextual_end(struct nk_context*);
1663/* =============================================================================
1664 *
1665 * TOOLTIP
1666 *
1667 * ============================================================================= */
1668NK_API void nk_tooltip(struct nk_context*, const char*);
1669NK_API int nk_tooltip_begin(struct nk_context*, float width);
1670NK_API void nk_tooltip_end(struct nk_context*);
1671/* =============================================================================
1672 *
1673 * MENU
1674 *
1675 * ============================================================================= */
1676NK_API void nk_menubar_begin(struct nk_context*);
1677NK_API void nk_menubar_end(struct nk_context*);
1678NK_API int nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size);
1679NK_API int nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size);
1680NK_API int nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size);
1681NK_API int nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size);
1682NK_API int nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size);
1683NK_API int nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size);
1684NK_API int nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size);
1685NK_API int nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size);
1686NK_API int nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align);
1687NK_API int nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment);
1688NK_API int nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);
1689NK_API int nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);
1690NK_API int nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
1691NK_API int nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);
1692NK_API void nk_menu_close(struct nk_context*);
1693NK_API void nk_menu_end(struct nk_context*);
1694/* =============================================================================
1695 *
1696 * STYLE
1697 *
1698 * ============================================================================= */
1699enum nk_style_colors {
1700 NK_COLOR_TEXT,
1701 NK_COLOR_WINDOW,
1702 NK_COLOR_HEADER,
1703 NK_COLOR_BORDER,
1704 NK_COLOR_BUTTON,
1705 NK_COLOR_BUTTON_HOVER,
1706 NK_COLOR_BUTTON_ACTIVE,
1707 NK_COLOR_TOGGLE,
1708 NK_COLOR_TOGGLE_HOVER,
1709 NK_COLOR_TOGGLE_CURSOR,
1710 NK_COLOR_SELECT,
1711 NK_COLOR_SELECT_ACTIVE,
1712 NK_COLOR_SLIDER,
1713 NK_COLOR_SLIDER_CURSOR,
1714 NK_COLOR_SLIDER_CURSOR_HOVER,
1715 NK_COLOR_SLIDER_CURSOR_ACTIVE,
1716 NK_COLOR_PROPERTY,
1717 NK_COLOR_EDIT,
1718 NK_COLOR_EDIT_CURSOR,
1719 NK_COLOR_COMBO,
1720 NK_COLOR_CHART,
1721 NK_COLOR_CHART_COLOR,
1722 NK_COLOR_CHART_COLOR_HIGHLIGHT,
1723 NK_COLOR_SCROLLBAR,
1724 NK_COLOR_SCROLLBAR_CURSOR,
1725 NK_COLOR_SCROLLBAR_CURSOR_HOVER,
1726 NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,
1727 NK_COLOR_TAB_HEADER,
1728 NK_COLOR_COUNT
1729};
1730enum nk_style_cursor {
1731 NK_CURSOR_ARROW,
1732 NK_CURSOR_TEXT,
1733 NK_CURSOR_MOVE,
1734 NK_CURSOR_RESIZE_VERTICAL,
1735 NK_CURSOR_RESIZE_HORIZONTAL,
1736 NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT,
1737 NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT,
1738 NK_CURSOR_COUNT
1739};
1740NK_API void nk_style_default(struct nk_context*);
1741NK_API void nk_style_from_table(struct nk_context*, const struct nk_color*);
1742NK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*);
1743NK_API void nk_style_load_all_cursors(struct nk_context*, struct nk_cursor*);
1744NK_API const char* nk_style_get_color_by_name(enum nk_style_colors);
1745NK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*);
1746NK_API int nk_style_set_cursor(struct nk_context*, enum nk_style_cursor);
1747NK_API void nk_style_show_cursor(struct nk_context*);
1748NK_API void nk_style_hide_cursor(struct nk_context*);
1749
1750NK_API int nk_style_push_font(struct nk_context*, struct nk_user_font*);
1751NK_API int nk_style_push_float(struct nk_context*, float*, float);
1752NK_API int nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2);
1753NK_API int nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item);
1754NK_API int nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags);
1755NK_API int nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color);
1756
1757NK_API int nk_style_pop_font(struct nk_context*);
1758NK_API int nk_style_pop_float(struct nk_context*);
1759NK_API int nk_style_pop_vec2(struct nk_context*);
1760NK_API int nk_style_pop_style_item(struct nk_context*);
1761NK_API int nk_style_pop_flags(struct nk_context*);
1762NK_API int nk_style_pop_color(struct nk_context*);
1763/* =============================================================================
1764 *
1765 * COLOR
1766 *
1767 * ============================================================================= */
1768NK_API struct nk_color nk_rgb(int r, int g, int b);
1769NK_API struct nk_color nk_rgb_iv(const int *rgb);
1770NK_API struct nk_color nk_rgb_bv(const nk_byte* rgb);
1771NK_API struct nk_color nk_rgb_f(float r, float g, float b);
1772NK_API struct nk_color nk_rgb_fv(const float *rgb);
1773NK_API struct nk_color nk_rgb_hex(const char *rgb);
1774
1775NK_API struct nk_color nk_rgba(int r, int g, int b, int a);
1776NK_API struct nk_color nk_rgba_u32(nk_uint);
1777NK_API struct nk_color nk_rgba_iv(const int *rgba);
1778NK_API struct nk_color nk_rgba_bv(const nk_byte *rgba);
1779NK_API struct nk_color nk_rgba_f(float r, float g, float b, float a);
1780NK_API struct nk_color nk_rgba_fv(const float *rgba);
1781NK_API struct nk_color nk_rgba_hex(const char *rgb);
1782
1783NK_API struct nk_color nk_hsv(int h, int s, int v);
1784NK_API struct nk_color nk_hsv_iv(const int *hsv);
1785NK_API struct nk_color nk_hsv_bv(const nk_byte *hsv);
1786NK_API struct nk_color nk_hsv_f(float h, float s, float v);
1787NK_API struct nk_color nk_hsv_fv(const float *hsv);
1788
1789NK_API struct nk_color nk_hsva(int h, int s, int v, int a);
1790NK_API struct nk_color nk_hsva_iv(const int *hsva);
1791NK_API struct nk_color nk_hsva_bv(const nk_byte *hsva);
1792NK_API struct nk_color nk_hsva_f(float h, float s, float v, float a);
1793NK_API struct nk_color nk_hsva_fv(const float *hsva);
1794
1795/* color (conversion nuklear --> user) */
1796NK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color);
1797NK_API void nk_color_fv(float *rgba_out, struct nk_color);
1798NK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color);
1799NK_API void nk_color_dv(double *rgba_out, struct nk_color);
1800
1801NK_API nk_uint nk_color_u32(struct nk_color);
1802NK_API void nk_color_hex_rgba(char *output, struct nk_color);
1803NK_API void nk_color_hex_rgb(char *output, struct nk_color);
1804
1805NK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color);
1806NK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color);
1807NK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color);
1808NK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color);
1809NK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color);
1810NK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color);
1811
1812NK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color);
1813NK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color);
1814NK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color);
1815NK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color);
1816NK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color);
1817NK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color);
1818/* =============================================================================
1819 *
1820 * IMAGE
1821 *
1822 * ============================================================================= */
1823NK_API nk_handle nk_handle_ptr(void*);
1824NK_API nk_handle nk_handle_id(int);
1825NK_API struct nk_image nk_image_handle(nk_handle);
1826NK_API struct nk_image nk_image_ptr(void*);
1827NK_API struct nk_image nk_image_id(int);
1828NK_API int nk_image_is_subimage(const struct nk_image* img);
1829NK_API struct nk_image nk_subimage_ptr(void*, unsigned short w, unsigned short h, struct nk_rect sub_region);
1830NK_API struct nk_image nk_subimage_id(int, unsigned short w, unsigned short h, struct nk_rect sub_region);
1831NK_API struct nk_image nk_subimage_handle(nk_handle, unsigned short w, unsigned short h, struct nk_rect sub_region);
1832/* =============================================================================
1833 *
1834 * MATH
1835 *
1836 * ============================================================================= */
1837NK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed);
1838NK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading);
1839
1840NK_API struct nk_vec2 nk_vec2(float x, float y);
1841NK_API struct nk_vec2 nk_vec2i(int x, int y);
1842NK_API struct nk_vec2 nk_vec2v(const float *xy);
1843NK_API struct nk_vec2 nk_vec2iv(const int *xy);
1844
1845NK_API struct nk_rect nk_get_null_rect(void);
1846NK_API struct nk_rect nk_rect(float x, float y, float w, float h);
1847NK_API struct nk_rect nk_recti(int x, int y, int w, int h);
1848NK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size);
1849NK_API struct nk_rect nk_rectv(const float *xywh);
1850NK_API struct nk_rect nk_rectiv(const int *xywh);
1851NK_API struct nk_vec2 nk_rect_pos(struct nk_rect);
1852NK_API struct nk_vec2 nk_rect_size(struct nk_rect);
1853/* =============================================================================
1854 *
1855 * STRING
1856 *
1857 * ============================================================================= */
1858NK_API int nk_strlen(const char *str);
1859NK_API int nk_stricmp(const char *s1, const char *s2);
1860NK_API int nk_stricmpn(const char *s1, const char *s2, int n);
1861NK_API int nk_strtoi(const char *str, const char **endptr);
1862NK_API float nk_strtof(const char *str, const char **endptr);
1863NK_API double nk_strtod(const char *str, const char **endptr);
1864NK_API int nk_strfilter(const char *text, const char *regexp);
1865NK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score);
1866NK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score);
1867/* =============================================================================
1868 *
1869 * UTF-8
1870 *
1871 * ============================================================================= */
1872NK_API int nk_utf_decode(const char*, nk_rune*, int);
1873NK_API int nk_utf_encode(nk_rune, char*, int);
1874NK_API int nk_utf_len(const char*, int byte_len);
1875NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len);
1876/* ===============================================================
1877 *
1878 * FONT
1879 *
1880 * ===============================================================*/
1881/* Font handling in this library was designed to be quite customizable and lets
1882 you decide what you want to use and what you want to provide. There are three
1883 different ways to use the font atlas. The first two will use your font
1884 handling scheme and only requires essential data to run nuklear. The next
1885 slightly more advanced features is font handling with vertex buffer output.
1886 Finally the most complex API wise is using nuklears font baking API.
1887
1888 1.) Using your own implementation without vertex buffer output
1889 --------------------------------------------------------------
1890 So first up the easiest way to do font handling is by just providing a
1891 `nk_user_font` struct which only requires the height in pixel of the used
1892 font and a callback to calculate the width of a string. This way of handling
1893 fonts is best fitted for using the normal draw shape command API where you
1894 do all the text drawing yourself and the library does not require any kind
1895 of deeper knowledge about which font handling mechanism you use.
1896 IMPORTANT: the `nk_user_font` pointer provided to nuklear has to persist
1897 over the complete life time! I know this sucks but it is currently the only
1898 way to switch between fonts.
1899
1900 float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)
1901 {
1902 your_font_type *type = handle.ptr;
1903 float text_width = ...;
1904 return text_width;
1905 }
1906
1907 struct nk_user_font font;
1908 font.userdata.ptr = &your_font_class_or_struct;
1909 font.height = your_font_height;
1910 font.width = your_text_width_calculation;
1911
1912 struct nk_context ctx;
1913 nk_init_default(&ctx, &font);
1914
1915 2.) Using your own implementation with vertex buffer output
1916 --------------------------------------------------------------
1917 While the first approach works fine if you don't want to use the optional
1918 vertex buffer output it is not enough if you do. To get font handling working
1919 for these cases you have to provide two additional parameters inside the
1920 `nk_user_font`. First a texture atlas handle used to draw text as subimages
1921 of a bigger font atlas texture and a callback to query a character's glyph
1922 information (offset, size, ...). So it is still possible to provide your own
1923 font and use the vertex buffer output.
1924
1925 float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)
1926 {
1927 your_font_type *type = handle.ptr;
1928 float text_width = ...;
1929 return text_width;
1930 }
1931 void query_your_font_glyph(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)
1932 {
1933 your_font_type *type = handle.ptr;
1934 glyph.width = ...;
1935 glyph.height = ...;
1936 glyph.xadvance = ...;
1937 glyph.uv[0].x = ...;
1938 glyph.uv[0].y = ...;
1939 glyph.uv[1].x = ...;
1940 glyph.uv[1].y = ...;
1941 glyph.offset.x = ...;
1942 glyph.offset.y = ...;
1943 }
1944
1945 struct nk_user_font font;
1946 font.userdata.ptr = &your_font_class_or_struct;
1947 font.height = your_font_height;
1948 font.width = your_text_width_calculation;
1949 font.query = query_your_font_glyph;
1950 font.texture.id = your_font_texture;
1951
1952 struct nk_context ctx;
1953 nk_init_default(&ctx, &font);
1954
1955 3.) Nuklear font baker
1956 ------------------------------------
1957 The final approach if you do not have a font handling functionality or don't
1958 want to use it in this library is by using the optional font baker.
1959 The font baker API's can be used to create a font plus font atlas texture
1960 and can be used with or without the vertex buffer output.
1961
1962 It still uses the `nk_user_font` struct and the two different approaches
1963 previously stated still work. The font baker is not located inside
1964 `nk_context` like all other systems since it can be understood as more of
1965 an extension to nuklear and does not really depend on any `nk_context` state.
1966
1967 Font baker need to be initialized first by one of the nk_font_atlas_init_xxx
1968 functions. If you don't care about memory just call the default version
1969 `nk_font_atlas_init_default` which will allocate all memory from the standard library.
1970 If you want to control memory allocation but you don't care if the allocated
1971 memory is temporary and therefore can be freed directly after the baking process
1972 is over or permanent you can call `nk_font_atlas_init`.
1973
1974 After successfull intializing the font baker you can add Truetype(.ttf) fonts from
1975 different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`.
1976 functions. Adding font will permanently store each font, font config and ttf memory block(!)
1977 inside the font atlas and allows to reuse the font atlas. If you don't want to reuse
1978 the font baker by for example adding additional fonts you can call
1979 `nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end).
1980
1981 As soon as you added all fonts you wanted you can now start the baking process
1982 for every selected glyphes to image by calling `nk_font_atlas_bake`.
1983 The baking process returns image memory, width and height which can be used to
1984 either create your own image object or upload it to any graphics library.
1985 No matter which case you finally have to call `nk_font_atlas_end` which
1986 will free all temporary memory including the font atlas image so make sure
1987 you created our texture beforehand. `nk_font_atlas_end` requires a handle
1988 to your font texture or object and optionally fills a `struct nk_draw_null_texture`
1989 which can be used for the optional vertex output. If you don't want it just
1990 set the argument to `NULL`.
1991
1992 At this point you are done and if you don't want to reuse the font atlas you
1993 can call `nk_font_atlas_cleanup` to free all truetype blobs and configuration
1994 memory. Finally if you don't use the font atlas and any of it's fonts anymore
1995 you need to call `nk_font_atlas_clear` to free all memory still being used.
1996
1997 struct nk_font_atlas atlas;
1998 nk_font_atlas_init_default(&atlas);
1999 nk_font_atlas_begin(&atlas);
2000 nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, 0);
2001 nk_font *font2 = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font2.ttf", 16, 0);
2002 const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32);
2003 nk_font_atlas_end(&atlas, nk_handle_id(texture), 0);
2004
2005 struct nk_context ctx;
2006 nk_init_default(&ctx, &font->handle);
2007 while (1) {
2008
2009 }
2010 nk_font_atlas_clear(&atlas);
2011
2012 The font baker API is probably the most complex API inside this library and
2013 I would suggest reading some of my examples `example/` to get a grip on how
2014 to use the font atlas. There are a number of details I left out. For example
2015 how to merge fonts, configure a font with `nk_font_config` to use other languages,
2016 use another texture coodinate format and a lot more:
2017
2018 struct nk_font_config cfg = nk_font_config(font_pixel_height);
2019 cfg.merge_mode = nk_false or nk_true;
2020 cfg.range = nk_font_korean_glyph_ranges();
2021 cfg.coord_type = NK_COORD_PIXEL;
2022 nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, &cfg);
2023
2024*/
2025struct nk_user_font_glyph;
2026typedef float(*nk_text_width_f)(nk_handle, float h, const char*, int len);
2027typedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height,
2028 struct nk_user_font_glyph *glyph,
2029 nk_rune codepoint, nk_rune next_codepoint);
2030
2031#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
2032struct nk_user_font_glyph {
2033 struct nk_vec2 uv[2];
2034 /* texture coordinates */
2035 struct nk_vec2 offset;
2036 /* offset between top left and glyph */
2037 float width, height;
2038 /* size of the glyph */
2039 float xadvance;
2040 /* offset to the next glyph */
2041};
2042#endif
2043
2044struct nk_user_font {
2045 nk_handle userdata;
2046 /* user provided font handle */
2047 float height;
2048 /* max height of the font */
2049 nk_text_width_f width;
2050 /* font string width in pixel callback */
2051#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
2052 nk_query_font_glyph_f query;
2053 /* font glyph callback to query drawing info */
2054 nk_handle texture;
2055 /* texture handle to the used font atlas or texture */
2056#endif
2057};
2058
2059#ifdef NK_INCLUDE_FONT_BAKING
2060enum nk_font_coord_type {
2061 NK_COORD_UV, /* texture coordinates inside font glyphs are clamped between 0-1 */
2062 NK_COORD_PIXEL /* texture coordinates inside font glyphs are in absolute pixel */
2063};
2064
2065struct nk_baked_font {
2066 float height;
2067 /* height of the font */
2068 float ascent, descent;
2069 /* font glyphs ascent and descent */
2070 nk_rune glyph_offset;
2071 /* glyph array offset inside the font glyph baking output array */
2072 nk_rune glyph_count;
2073 /* number of glyphs of this font inside the glyph baking array output */
2074 const nk_rune *ranges;
2075 /* font codepoint ranges as pairs of (from/to) and 0 as last element */
2076};
2077
2078struct nk_font_config {
2079 struct nk_font_config *next;
2080 /* NOTE: only used internally */
2081 void *ttf_blob;
2082 /* pointer to loaded TTF file memory block.
2083 * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */
2084 nk_size ttf_size;
2085 /* size of the loaded TTF file memory block
2086 * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */
2087
2088 unsigned char ttf_data_owned_by_atlas;
2089 /* used inside font atlas: default to: 0*/
2090 unsigned char merge_mode;
2091 /* merges this font into the last font */
2092 unsigned char pixel_snap;
2093 /* align every character to pixel boundary (if true set oversample (1,1)) */
2094 unsigned char oversample_v, oversample_h;
2095 /* rasterize at hight quality for sub-pixel position */
2096 unsigned char padding[3];
2097
2098 float size;
2099 /* baked pixel height of the font */
2100 enum nk_font_coord_type coord_type;
2101 /* texture coordinate format with either pixel or UV coordinates */
2102 struct nk_vec2 spacing;
2103 /* extra pixel spacing between glyphs */
2104 const nk_rune *range;
2105 /* list of unicode ranges (2 values per range, zero terminated) */
2106 struct nk_baked_font *font;
2107 /* font to setup in the baking process: NOTE: not needed for font atlas */
2108 nk_rune fallback_glyph;
2109 /* fallback glyph to use if a given rune is not found */
2110};
2111
2112struct nk_font_glyph {
2113 nk_rune codepoint;
2114 float xadvance;
2115 float x0, y0, x1, y1, w, h;
2116 float u0, v0, u1, v1;
2117};
2118
2119struct nk_font {
2120 struct nk_font *next;
2121 struct nk_user_font handle;
2122 struct nk_baked_font info;
2123 float scale;
2124 struct nk_font_glyph *glyphs;
2125 const struct nk_font_glyph *fallback;
2126 nk_rune fallback_codepoint;
2127 nk_handle texture;
2128 struct nk_font_config *config;
2129};
2130
2131enum nk_font_atlas_format {
2132 NK_FONT_ATLAS_ALPHA8,
2133 NK_FONT_ATLAS_RGBA32
2134};
2135
2136struct nk_font_atlas {
2137 void *pixel;
2138 int tex_width;
2139 int tex_height;
2140
2141 struct nk_allocator permanent;
2142 struct nk_allocator temporary;
2143
2144 struct nk_recti custom;
2145 struct nk_cursor cursors[NK_CURSOR_COUNT];
2146
2147 int glyph_count;
2148 struct nk_font_glyph *glyphs;
2149 struct nk_font *default_font;
2150 struct nk_font *fonts;
2151 struct nk_font_config *config;
2152 int font_num;
2153};
2154
2155/* some language glyph codepoint ranges */
2156NK_API const nk_rune *nk_font_default_glyph_ranges(void);
2157NK_API const nk_rune *nk_font_chinese_glyph_ranges(void);
2158NK_API const nk_rune *nk_font_cyrillic_glyph_ranges(void);
2159NK_API const nk_rune *nk_font_korean_glyph_ranges(void);
2160
2161#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
2162NK_API void nk_font_atlas_init_default(struct nk_font_atlas*);
2163#endif
2164NK_API void nk_font_atlas_init(struct nk_font_atlas*, struct nk_allocator*);
2165NK_API void nk_font_atlas_init_custom(struct nk_font_atlas*, struct nk_allocator *persistent, struct nk_allocator *transient);
2166NK_API void nk_font_atlas_begin(struct nk_font_atlas*);
2167NK_API struct nk_font_config nk_font_config(float pixel_height);
2168NK_API struct nk_font *nk_font_atlas_add(struct nk_font_atlas*, const struct nk_font_config*);
2169#ifdef NK_INCLUDE_DEFAULT_FONT
2170NK_API struct nk_font* nk_font_atlas_add_default(struct nk_font_atlas*, float height, const struct nk_font_config*);
2171#endif
2172NK_API struct nk_font* nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, nk_size size, float height, const struct nk_font_config *config);
2173#ifdef NK_INCLUDE_STANDARD_IO
2174NK_API struct nk_font* nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, float height, const struct nk_font_config*);
2175#endif
2176NK_API struct nk_font *nk_font_atlas_add_compressed(struct nk_font_atlas*, void *memory, nk_size size, float height, const struct nk_font_config*);
2177NK_API struct nk_font* nk_font_atlas_add_compressed_base85(struct nk_font_atlas*, const char *data, float height, const struct nk_font_config *config);
2178NK_API const void* nk_font_atlas_bake(struct nk_font_atlas*, int *width, int *height, enum nk_font_atlas_format);
2179NK_API void nk_font_atlas_end(struct nk_font_atlas*, nk_handle tex, struct nk_draw_null_texture*);
2180NK_API const struct nk_font_glyph* nk_font_find_glyph(struct nk_font*, nk_rune unicode);
2181NK_API void nk_font_atlas_cleanup(struct nk_font_atlas *atlas);
2182NK_API void nk_font_atlas_clear(struct nk_font_atlas*);
2183
2184#endif
2185
2186/* ==============================================================
2187 *
2188 * MEMORY BUFFER
2189 *
2190 * ===============================================================*/
2191/* A basic (double)-buffer with linear allocation and resetting as only
2192 freeing policy. The buffer's main purpose is to control all memory management
2193 inside the GUI toolkit and still leave memory control as much as possible in
2194 the hand of the user while also making sure the library is easy to use if
2195 not as much control is needed.
2196 In general all memory inside this library can be provided from the user in
2197 three different ways.
2198
2199 The first way and the one providing most control is by just passing a fixed
2200 size memory block. In this case all control lies in the hand of the user
2201 since he can exactly control where the memory comes from and how much memory
2202 the library should consume. Of course using the fixed size API removes the
2203 ability to automatically resize a buffer if not enough memory is provided so
2204 you have to take over the resizing. While being a fixed sized buffer sounds
2205 quite limiting, it is very effective in this library since the actual memory
2206 consumption is quite stable and has a fixed upper bound for a lot of cases.
2207
2208 If you don't want to think about how much memory the library should allocate
2209 at all time or have a very dynamic UI with unpredictable memory consumption
2210 habits but still want control over memory allocation you can use the dynamic
2211 allocator based API. The allocator consists of two callbacks for allocating
2212 and freeing memory and optional userdata so you can plugin your own allocator.
2213
2214 The final and easiest way can be used by defining
2215 NK_INCLUDE_DEFAULT_ALLOCATOR which uses the standard library memory
2216 allocation functions malloc and free and takes over complete control over
2217 memory in this library.
2218*/
2219struct nk_memory_status {
2220 void *memory;
2221 unsigned int type;
2222 nk_size size;
2223 nk_size allocated;
2224 nk_size needed;
2225 nk_size calls;
2226};
2227
2228enum nk_allocation_type {
2229 NK_BUFFER_FIXED,
2230 NK_BUFFER_DYNAMIC
2231};
2232
2233enum nk_buffer_allocation_type {
2234 NK_BUFFER_FRONT,
2235 NK_BUFFER_BACK,
2236 NK_BUFFER_MAX
2237};
2238
2239struct nk_buffer_marker {
2240 int active;
2241 nk_size offset;
2242};
2243
2244struct nk_memory {void *ptr;nk_size size;};
2245struct nk_buffer {
2246 struct nk_buffer_marker marker[NK_BUFFER_MAX];
2247 /* buffer marker to free a buffer to a certain offset */
2248 struct nk_allocator pool;
2249 /* allocator callback for dynamic buffers */
2250 enum nk_allocation_type type;
2251 /* memory management type */
2252 struct nk_memory memory;
2253 /* memory and size of the current memory block */
2254 float grow_factor;
2255 /* growing factor for dynamic memory management */
2256 nk_size allocated;
2257 /* total amount of memory allocated */
2258 nk_size needed;
2259 /* totally consumed memory given that enough memory is present */
2260 nk_size calls;
2261 /* number of allocation calls */
2262 nk_size size;
2263 /* current size of the buffer */
2264};
2265
2266#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
2267NK_API void nk_buffer_init_default(struct nk_buffer*);
2268#endif
2269NK_API void nk_buffer_init(struct nk_buffer*, const struct nk_allocator*, nk_size size);
2270NK_API void nk_buffer_init_fixed(struct nk_buffer*, void *memory, nk_size size);
2271NK_API void nk_buffer_info(struct nk_memory_status*, struct nk_buffer*);
2272NK_API void nk_buffer_push(struct nk_buffer*, enum nk_buffer_allocation_type type, const void *memory, nk_size size, nk_size align);
2273NK_API void nk_buffer_mark(struct nk_buffer*, enum nk_buffer_allocation_type type);
2274NK_API void nk_buffer_reset(struct nk_buffer*, enum nk_buffer_allocation_type type);
2275NK_API void nk_buffer_clear(struct nk_buffer*);
2276NK_API void nk_buffer_free(struct nk_buffer*);
2277NK_API void *nk_buffer_memory(struct nk_buffer*);
2278NK_API const void *nk_buffer_memory_const(const struct nk_buffer*);
2279NK_API nk_size nk_buffer_total(struct nk_buffer*);
2280
2281/* ==============================================================
2282 *
2283 * STRING
2284 *
2285 * ===============================================================*/
2286/* Basic string buffer which is only used in context with the text editor
2287 * to manage and manipulate dynamic or fixed size string content. This is _NOT_
2288 * the default string handling method. The only instance you should have any contact
2289 * with this API is if you interact with an `nk_text_edit` object inside one of the
2290 * copy and paste functions and even there only for more advanced cases. */
2291struct nk_str {
2292 struct nk_buffer buffer;
2293 int len; /* in codepoints/runes/glyphs */
2294};
2295
2296#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
2297NK_API void nk_str_init_default(struct nk_str*);
2298#endif
2299NK_API void nk_str_init(struct nk_str*, const struct nk_allocator*, nk_size size);
2300NK_API void nk_str_init_fixed(struct nk_str*, void *memory, nk_size size);
2301NK_API void nk_str_clear(struct nk_str*);
2302NK_API void nk_str_free(struct nk_str*);
2303
2304NK_API int nk_str_append_text_char(struct nk_str*, const char*, int);
2305NK_API int nk_str_append_str_char(struct nk_str*, const char*);
2306NK_API int nk_str_append_text_utf8(struct nk_str*, const char*, int);
2307NK_API int nk_str_append_str_utf8(struct nk_str*, const char*);
2308NK_API int nk_str_append_text_runes(struct nk_str*, const nk_rune*, int);
2309NK_API int nk_str_append_str_runes(struct nk_str*, const nk_rune*);
2310
2311NK_API int nk_str_insert_at_char(struct nk_str*, int pos, const char*, int);
2312NK_API int nk_str_insert_at_rune(struct nk_str*, int pos, const char*, int);
2313
2314NK_API int nk_str_insert_text_char(struct nk_str*, int pos, const char*, int);
2315NK_API int nk_str_insert_str_char(struct nk_str*, int pos, const char*);
2316NK_API int nk_str_insert_text_utf8(struct nk_str*, int pos, const char*, int);
2317NK_API int nk_str_insert_str_utf8(struct nk_str*, int pos, const char*);
2318NK_API int nk_str_insert_text_runes(struct nk_str*, int pos, const nk_rune*, int);
2319NK_API int nk_str_insert_str_runes(struct nk_str*, int pos, const nk_rune*);
2320
2321NK_API void nk_str_remove_chars(struct nk_str*, int len);
2322NK_API void nk_str_remove_runes(struct nk_str *str, int len);
2323NK_API void nk_str_delete_chars(struct nk_str*, int pos, int len);
2324NK_API void nk_str_delete_runes(struct nk_str*, int pos, int len);
2325
2326NK_API char *nk_str_at_char(struct nk_str*, int pos);
2327NK_API char *nk_str_at_rune(struct nk_str*, int pos, nk_rune *unicode, int *len);
2328NK_API nk_rune nk_str_rune_at(const struct nk_str*, int pos);
2329NK_API const char *nk_str_at_char_const(const struct nk_str*, int pos);
2330NK_API const char *nk_str_at_const(const struct nk_str*, int pos, nk_rune *unicode, int *len);
2331
2332NK_API char *nk_str_get(struct nk_str*);
2333NK_API const char *nk_str_get_const(const struct nk_str*);
2334NK_API int nk_str_len(struct nk_str*);
2335NK_API int nk_str_len_char(struct nk_str*);
2336
2337/*===============================================================
2338 *
2339 * TEXT EDITOR
2340 *
2341 * ===============================================================*/
2342/* Editing text in this library is handled by either `nk_edit_string` or
2343 * `nk_edit_buffer`. But like almost everything in this library there are multiple
2344 * ways of doing it and a balance between control and ease of use with memory
2345 * as well as functionality controlled by flags.
2346 *
2347 * This library generally allows three different levels of memory control:
2348 * First of is the most basic way of just providing a simple char array with
2349 * string length. This method is probably the easiest way of handling simple
2350 * user text input. Main upside is complete control over memory while the biggest
2351 * downside in comparsion with the other two approaches is missing undo/redo.
2352 *
2353 * For UIs that require undo/redo the second way was created. It is based on
2354 * a fixed size nk_text_edit struct, which has an internal undo/redo stack.
2355 * This is mainly useful if you want something more like a text editor but don't want
2356 * to have a dynamically growing buffer.
2357 *
2358 * The final way is using a dynamically growing nk_text_edit struct, which
2359 * has both a default version if you don't care where memory comes from and an
2360 * allocator version if you do. While the text editor is quite powerful for its
2361 * complexity I would not recommend editing gigabytes of data with it.
2362 * It is rather designed for uses cases which make sense for a GUI library not for
2363 * an full blown text editor.
2364 */
2365#ifndef NK_TEXTEDIT_UNDOSTATECOUNT
2366#define NK_TEXTEDIT_UNDOSTATECOUNT 99
2367#endif
2368
2369#ifndef NK_TEXTEDIT_UNDOCHARCOUNT
2370#define NK_TEXTEDIT_UNDOCHARCOUNT 999
2371#endif
2372
2373struct nk_text_edit;
2374struct nk_clipboard {
2375 nk_handle userdata;
2376 nk_plugin_paste paste;
2377 nk_plugin_copy copy;
2378};
2379
2380struct nk_text_undo_record {
2381 int where;
2382 short insert_length;
2383 short delete_length;
2384 short char_storage;
2385};
2386
2387struct nk_text_undo_state {
2388 struct nk_text_undo_record undo_rec[NK_TEXTEDIT_UNDOSTATECOUNT];
2389 nk_rune undo_char[NK_TEXTEDIT_UNDOCHARCOUNT];
2390 short undo_point;
2391 short redo_point;
2392 short undo_char_point;
2393 short redo_char_point;
2394};
2395
2396enum nk_text_edit_type {
2397 NK_TEXT_EDIT_SINGLE_LINE,
2398 NK_TEXT_EDIT_MULTI_LINE
2399};
2400
2401enum nk_text_edit_mode {
2402 NK_TEXT_EDIT_MODE_VIEW,
2403 NK_TEXT_EDIT_MODE_INSERT,
2404 NK_TEXT_EDIT_MODE_REPLACE
2405};
2406
2407struct nk_text_edit {
2408 struct nk_clipboard clip;
2409 struct nk_str string;
2410 nk_plugin_filter filter;
2411 struct nk_vec2 scrollbar;
2412
2413 int cursor;
2414 int select_start;
2415 int select_end;
2416 unsigned char mode;
2417 unsigned char cursor_at_end_of_line;
2418 unsigned char initialized;
2419 unsigned char has_preferred_x;
2420 unsigned char single_line;
2421 unsigned char active;
2422 unsigned char padding1;
2423 float preferred_x;
2424 struct nk_text_undo_state undo;
2425};
2426
2427/* filter function */
2428NK_API int nk_filter_default(const struct nk_text_edit*, nk_rune unicode);
2429NK_API int nk_filter_ascii(const struct nk_text_edit*, nk_rune unicode);
2430NK_API int nk_filter_float(const struct nk_text_edit*, nk_rune unicode);
2431NK_API int nk_filter_decimal(const struct nk_text_edit*, nk_rune unicode);
2432NK_API int nk_filter_hex(const struct nk_text_edit*, nk_rune unicode);
2433NK_API int nk_filter_oct(const struct nk_text_edit*, nk_rune unicode);
2434NK_API int nk_filter_binary(const struct nk_text_edit*, nk_rune unicode);
2435
2436/* text editor */
2437#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
2438NK_API void nk_textedit_init_default(struct nk_text_edit*);
2439#endif
2440NK_API void nk_textedit_init(struct nk_text_edit*, struct nk_allocator*, nk_size size);
2441NK_API void nk_textedit_init_fixed(struct nk_text_edit*, void *memory, nk_size size);
2442NK_API void nk_textedit_free(struct nk_text_edit*);
2443NK_API void nk_textedit_text(struct nk_text_edit*, const char*, int total_len);
2444NK_API void nk_textedit_delete(struct nk_text_edit*, int where, int len);
2445NK_API void nk_textedit_delete_selection(struct nk_text_edit*);
2446NK_API void nk_textedit_select_all(struct nk_text_edit*);
2447NK_API int nk_textedit_cut(struct nk_text_edit*);
2448NK_API int nk_textedit_paste(struct nk_text_edit*, char const*, int len);
2449NK_API void nk_textedit_undo(struct nk_text_edit*);
2450NK_API void nk_textedit_redo(struct nk_text_edit*);
2451
2452/* ===============================================================
2453 *
2454 * DRAWING
2455 *
2456 * ===============================================================*/
2457/* This library was designed to be render backend agnostic so it does
2458 not draw anything to screen. Instead all drawn shapes, widgets
2459 are made of, are buffered into memory and make up a command queue.
2460 Each frame therefore fills the command buffer with draw commands
2461 that then need to be executed by the user and his own render backend.
2462 After that the command buffer needs to be cleared and a new frame can be
2463 started. It is probably important to note that the command buffer is the main
2464 drawing API and the optional vertex buffer API only takes this format and
2465 converts it into a hardware accessible format.
2466
2467 To use the command queue to draw your own widgets you can access the
2468 command buffer of each window by calling `nk_window_get_canvas` after
2469 previously having called `nk_begin`:
2470
2471 void draw_red_rectangle_widget(struct nk_context *ctx)
2472 {
2473 struct nk_command_buffer *canvas;
2474 struct nk_input *input = &ctx->input;
2475 canvas = nk_window_get_canvas(ctx);
2476
2477 struct nk_rect space;
2478 enum nk_widget_layout_states state;
2479 state = nk_widget(&space, ctx);
2480 if (!state) return;
2481
2482 if (state != NK_WIDGET_ROM)
2483 update_your_widget_by_user_input(...);
2484 nk_fill_rect(canvas, space, 0, nk_rgb(255,0,0));
2485 }
2486
2487 if (nk_begin(...)) {
2488 nk_layout_row_dynamic(ctx, 25, 1);
2489 draw_red_rectangle_widget(ctx);
2490 }
2491 nk_end(..)
2492
2493 Important to know if you want to create your own widgets is the `nk_widget`
2494 call. It allocates space on the panel reserved for this widget to be used,
2495 but also returns the state of the widget space. If your widget is not seen and does
2496 not have to be updated it is '0' and you can just return. If it only has
2497 to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both
2498 update and draw your widget. The reason for seperating is to only draw and
2499 update what is actually neccessary which is crucial for performance.
2500*/
2501enum nk_command_type {
2502 NK_COMMAND_NOP,
2503 NK_COMMAND_SCISSOR,
2504 NK_COMMAND_LINE,
2505 NK_COMMAND_CURVE,
2506 NK_COMMAND_RECT,
2507 NK_COMMAND_RECT_FILLED,
2508 NK_COMMAND_RECT_MULTI_COLOR,
2509 NK_COMMAND_CIRCLE,
2510 NK_COMMAND_CIRCLE_FILLED,
2511 NK_COMMAND_ARC,
2512 NK_COMMAND_ARC_FILLED,
2513 NK_COMMAND_TRIANGLE,
2514 NK_COMMAND_TRIANGLE_FILLED,
2515 NK_COMMAND_POLYGON,
2516 NK_COMMAND_POLYGON_FILLED,
2517 NK_COMMAND_POLYLINE,
2518 NK_COMMAND_TEXT,
2519 NK_COMMAND_IMAGE,
2520 NK_COMMAND_CUSTOM
2521};
2522
2523/* command base and header of every command inside the buffer */
2524struct nk_command {
2525 enum nk_command_type type;
2526 nk_size next;
2527#ifdef NK_INCLUDE_COMMAND_USERDATA
2528 nk_handle userdata;
2529#endif
2530};
2531
2532struct nk_command_scissor {
2533 struct nk_command header;
2534 short x, y;
2535 unsigned short w, h;
2536};
2537
2538struct nk_command_line {
2539 struct nk_command header;
2540 unsigned short line_thickness;
2541 struct nk_vec2i begin;
2542 struct nk_vec2i end;
2543 struct nk_color color;
2544};
2545
2546struct nk_command_curve {
2547 struct nk_command header;
2548 unsigned short line_thickness;
2549 struct nk_vec2i begin;
2550 struct nk_vec2i end;
2551 struct nk_vec2i ctrl[2];
2552 struct nk_color color;
2553};
2554
2555struct nk_command_rect {
2556 struct nk_command header;
2557 unsigned short rounding;
2558 unsigned short line_thickness;
2559 short x, y;
2560 unsigned short w, h;
2561 struct nk_color color;
2562};
2563
2564struct nk_command_rect_filled {
2565 struct nk_command header;
2566 unsigned short rounding;
2567 short x, y;
2568 unsigned short w, h;
2569 struct nk_color color;
2570};
2571
2572struct nk_command_rect_multi_color {
2573 struct nk_command header;
2574 short x, y;
2575 unsigned short w, h;
2576 struct nk_color left;
2577 struct nk_color top;
2578 struct nk_color bottom;
2579 struct nk_color right;
2580};
2581
2582struct nk_command_triangle {
2583 struct nk_command header;
2584 unsigned short line_thickness;
2585 struct nk_vec2i a;
2586 struct nk_vec2i b;
2587 struct nk_vec2i c;
2588 struct nk_color color;
2589};
2590
2591struct nk_command_triangle_filled {
2592 struct nk_command header;
2593 struct nk_vec2i a;
2594 struct nk_vec2i b;
2595 struct nk_vec2i c;
2596 struct nk_color color;
2597};
2598
2599struct nk_command_circle {
2600 struct nk_command header;
2601 short x, y;
2602 unsigned short line_thickness;
2603 unsigned short w, h;
2604 struct nk_color color;
2605};
2606
2607struct nk_command_circle_filled {
2608 struct nk_command header;
2609 short x, y;
2610 unsigned short w, h;
2611 struct nk_color color;
2612};
2613
2614struct nk_command_arc {
2615 struct nk_command header;
2616 short cx, cy;
2617 unsigned short r;
2618 unsigned short line_thickness;
2619 float a[2];
2620 struct nk_color color;
2621};
2622
2623struct nk_command_arc_filled {
2624 struct nk_command header;
2625 short cx, cy;
2626 unsigned short r;
2627 float a[2];
2628 struct nk_color color;
2629};
2630
2631struct nk_command_polygon {
2632 struct nk_command header;
2633 struct nk_color color;
2634 unsigned short line_thickness;
2635 unsigned short point_count;
2636 struct nk_vec2i points[1];
2637};
2638
2639struct nk_command_polygon_filled {
2640 struct nk_command header;
2641 struct nk_color color;
2642 unsigned short point_count;
2643 struct nk_vec2i points[1];
2644};
2645
2646struct nk_command_polyline {
2647 struct nk_command header;
2648 struct nk_color color;
2649 unsigned short line_thickness;
2650 unsigned short point_count;
2651 struct nk_vec2i points[1];
2652};
2653
2654struct nk_command_image {
2655 struct nk_command header;
2656 short x, y;
2657 unsigned short w, h;
2658 struct nk_image img;
2659 struct nk_color col;
2660};
2661
2662typedef void (*nk_command_custom_callback)(void *canvas, short x,short y,
2663 unsigned short w, unsigned short h, nk_handle callback_data);
2664struct nk_command_custom {
2665 struct nk_command header;
2666 short x, y;
2667 unsigned short w, h;
2668 nk_handle callback_data;
2669 nk_command_custom_callback callback;
2670};
2671
2672struct nk_command_text {
2673 struct nk_command header;
2674 const struct nk_user_font *font;
2675 struct nk_color background;
2676 struct nk_color foreground;
2677 short x, y;
2678 unsigned short w, h;
2679 float height;
2680 int length;
2681 char string[1];
2682};
2683
2684enum nk_command_clipping {
2685 NK_CLIPPING_OFF = nk_false,
2686 NK_CLIPPING_ON = nk_true
2687};
2688
2689struct nk_command_buffer {
2690 struct nk_buffer *base;
2691 struct nk_rect clip;
2692 int use_clipping;
2693 nk_handle userdata;
2694 nk_size begin, end, last;
2695};
2696
2697/* shape outlines */
2698NK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color);
2699NK_API void nk_stroke_curve(struct nk_command_buffer*, float, float, float, float, float, float, float, float, float line_thickness, struct nk_color);
2700NK_API void nk_stroke_rect(struct nk_command_buffer*, struct nk_rect, float rounding, float line_thickness, struct nk_color);
2701NK_API void nk_stroke_circle(struct nk_command_buffer*, struct nk_rect, float line_thickness, struct nk_color);
2702NK_API void nk_stroke_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, float line_thickness, struct nk_color);
2703NK_API void nk_stroke_triangle(struct nk_command_buffer*, float, float, float, float, float, float, float line_thichness, struct nk_color);
2704NK_API void nk_stroke_polyline(struct nk_command_buffer*, float *points, int point_count, float line_thickness, struct nk_color col);
2705NK_API void nk_stroke_polygon(struct nk_command_buffer*, float*, int point_count, float line_thickness, struct nk_color);
2706
2707/* filled shades */
2708NK_API void nk_fill_rect(struct nk_command_buffer*, struct nk_rect, float rounding, struct nk_color);
2709NK_API void nk_fill_rect_multi_color(struct nk_command_buffer*, struct nk_rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom);
2710NK_API void nk_fill_circle(struct nk_command_buffer*, struct nk_rect, struct nk_color);
2711NK_API void nk_fill_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, struct nk_color);
2712NK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, float x1, float y1, float x2, float y2, struct nk_color);
2713NK_API void nk_fill_polygon(struct nk_command_buffer*, float*, int point_count, struct nk_color);
2714
2715/* misc */
2716NK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color);
2717NK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color);
2718NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect);
2719NK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr);
2720
2721/* ===============================================================
2722 *
2723 * INPUT
2724 *
2725 * ===============================================================*/
2726struct nk_mouse_button {
2727 int down;
2728 unsigned int clicked;
2729 struct nk_vec2 clicked_pos;
2730};
2731struct nk_mouse {
2732 struct nk_mouse_button buttons[NK_BUTTON_MAX];
2733 struct nk_vec2 pos;
2734 struct nk_vec2 prev;
2735 struct nk_vec2 delta;
2736 struct nk_vec2 scroll_delta;
2737 unsigned char grab;
2738 unsigned char grabbed;
2739 unsigned char ungrab;
2740};
2741
2742struct nk_key {
2743 int down;
2744 unsigned int clicked;
2745};
2746struct nk_keyboard {
2747 struct nk_key keys[NK_KEY_MAX];
2748 char text[NK_INPUT_MAX];
2749 int text_len;
2750};
2751
2752struct nk_input {
2753 struct nk_keyboard keyboard;
2754 struct nk_mouse mouse;
2755};
2756
2757NK_API int nk_input_has_mouse_click(const struct nk_input*, enum nk_buttons);
2758NK_API int nk_input_has_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);
2759NK_API int nk_input_has_mouse_click_down_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect, int down);
2760NK_API int nk_input_is_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);
2761NK_API int nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, struct nk_rect b, int down);
2762NK_API int nk_input_any_mouse_click_in_rect(const struct nk_input*, struct nk_rect);
2763NK_API int nk_input_is_mouse_prev_hovering_rect(const struct nk_input*, struct nk_rect);
2764NK_API int nk_input_is_mouse_hovering_rect(const struct nk_input*, struct nk_rect);
2765NK_API int nk_input_mouse_clicked(const struct nk_input*, enum nk_buttons, struct nk_rect);
2766NK_API int nk_input_is_mouse_down(const struct nk_input*, enum nk_buttons);
2767NK_API int nk_input_is_mouse_pressed(const struct nk_input*, enum nk_buttons);
2768NK_API int nk_input_is_mouse_released(const struct nk_input*, enum nk_buttons);
2769NK_API int nk_input_is_key_pressed(const struct nk_input*, enum nk_keys);
2770NK_API int nk_input_is_key_released(const struct nk_input*, enum nk_keys);
2771NK_API int nk_input_is_key_down(const struct nk_input*, enum nk_keys);
2772
2773/* ===============================================================
2774 *
2775 * DRAW LIST
2776 *
2777 * ===============================================================*/
2778#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
2779/* The optional vertex buffer draw list provides a 2D drawing context
2780 with antialiasing functionality which takes basic filled or outlined shapes
2781 or a path and outputs vertexes, elements and draw commands.
2782 The actual draw list API is not required to be used directly while using this
2783 library since converting the default library draw command output is done by
2784 just calling `nk_convert` but I decided to still make this library accessible
2785 since it can be useful.
2786
2787 The draw list is based on a path buffering and polygon and polyline
2788 rendering API which allows a lot of ways to draw 2D content to screen.
2789 In fact it is probably more powerful than needed but allows even more crazy
2790 things than this library provides by default.
2791*/
2792typedef nk_ushort nk_draw_index;
2793enum nk_draw_list_stroke {
2794 NK_STROKE_OPEN = nk_false,
2795 /* build up path has no connection back to the beginning */
2796 NK_STROKE_CLOSED = nk_true
2797 /* build up path has a connection back to the beginning */
2798};
2799
2800enum nk_draw_vertex_layout_attribute {
2801 NK_VERTEX_POSITION,
2802 NK_VERTEX_COLOR,
2803 NK_VERTEX_TEXCOORD,
2804 NK_VERTEX_ATTRIBUTE_COUNT
2805};
2806
2807enum nk_draw_vertex_layout_format {
2808 NK_FORMAT_SCHAR,
2809 NK_FORMAT_SSHORT,
2810 NK_FORMAT_SINT,
2811 NK_FORMAT_UCHAR,
2812 NK_FORMAT_USHORT,
2813 NK_FORMAT_UINT,
2814 NK_FORMAT_FLOAT,
2815 NK_FORMAT_DOUBLE,
2816
2817NK_FORMAT_COLOR_BEGIN,
2818 NK_FORMAT_R8G8B8 = NK_FORMAT_COLOR_BEGIN,
2819 NK_FORMAT_R16G15B16,
2820 NK_FORMAT_R32G32B32,
2821
2822 NK_FORMAT_R8G8B8A8,
2823 NK_FORMAT_R16G15B16A16,
2824 NK_FORMAT_R32G32B32A32,
2825 NK_FORMAT_R32G32B32A32_FLOAT,
2826 NK_FORMAT_R32G32B32A32_DOUBLE,
2827
2828 NK_FORMAT_RGB32,
2829 NK_FORMAT_RGBA32,
2830NK_FORMAT_COLOR_END = NK_FORMAT_RGBA32,
2831 NK_FORMAT_COUNT
2832};
2833
2834#define NK_VERTEX_LAYOUT_END NK_VERTEX_ATTRIBUTE_COUNT,NK_FORMAT_COUNT,0
2835struct nk_draw_vertex_layout_element {
2836 enum nk_draw_vertex_layout_attribute attribute;
2837 enum nk_draw_vertex_layout_format format;
2838 nk_size offset;
2839};
2840
2841struct nk_draw_command {
2842 unsigned int elem_count;
2843 /* number of elements in the current draw batch */
2844 struct nk_rect clip_rect;
2845 /* current screen clipping rectangle */
2846 nk_handle texture;
2847 /* current texture to set */
2848#ifdef NK_INCLUDE_COMMAND_USERDATA
2849 nk_handle userdata;
2850#endif
2851};
2852
2853struct nk_draw_list {
2854 struct nk_rect clip_rect;
2855 struct nk_vec2 circle_vtx[12];
2856 struct nk_convert_config config;
2857
2858 struct nk_buffer *buffer;
2859 struct nk_buffer *vertices;
2860 struct nk_buffer *elements;
2861
2862 unsigned int element_count;
2863 unsigned int vertex_count;
2864 unsigned int cmd_count;
2865 nk_size cmd_offset;
2866
2867 unsigned int path_count;
2868 unsigned int path_offset;
2869
2870#ifdef NK_INCLUDE_COMMAND_USERDATA
2871 nk_handle userdata;
2872#endif
2873};
2874
2875/* draw list */
2876NK_API void nk_draw_list_init(struct nk_draw_list*);
2877NK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements);
2878NK_API void nk_draw_list_clear(struct nk_draw_list*);
2879
2880/* drawing */
2881#define nk_draw_list_foreach(cmd, can, b) for((cmd)=nk__draw_list_begin(can, b); (cmd)!=0; (cmd)=nk__draw_list_next(cmd, b, can))
2882NK_API const struct nk_draw_command* nk__draw_list_begin(const struct nk_draw_list*, const struct nk_buffer*);
2883NK_API const struct nk_draw_command* nk__draw_list_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_draw_list*);
2884NK_API const struct nk_draw_command* nk__draw_list_end(const struct nk_draw_list*, const struct nk_buffer*);
2885NK_API void nk_draw_list_clear(struct nk_draw_list *list);
2886
2887/* path */
2888NK_API void nk_draw_list_path_clear(struct nk_draw_list*);
2889NK_API void nk_draw_list_path_line_to(struct nk_draw_list*, struct nk_vec2 pos);
2890NK_API void nk_draw_list_path_arc_to_fast(struct nk_draw_list*, struct nk_vec2 center, float radius, int a_min, int a_max);
2891NK_API void nk_draw_list_path_arc_to(struct nk_draw_list*, struct nk_vec2 center, float radius, float a_min, float a_max, unsigned int segments);
2892NK_API void nk_draw_list_path_rect_to(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, float rounding);
2893NK_API void nk_draw_list_path_curve_to(struct nk_draw_list*, struct nk_vec2 p2, struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments);
2894NK_API void nk_draw_list_path_fill(struct nk_draw_list*, struct nk_color);
2895NK_API void nk_draw_list_path_stroke(struct nk_draw_list*, struct nk_color, enum nk_draw_list_stroke closed, float thickness);
2896
2897/* stroke */
2898NK_API void nk_draw_list_stroke_line(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_color, float thickness);
2899NK_API void nk_draw_list_stroke_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding, float thickness);
2900NK_API void nk_draw_list_stroke_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color, float thickness);
2901NK_API void nk_draw_list_stroke_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color, unsigned int segs, float thickness);
2902NK_API void nk_draw_list_stroke_curve(struct nk_draw_list*, struct nk_vec2 p0, struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, struct nk_color, unsigned int segments, float thickness);
2903NK_API void nk_draw_list_stroke_poly_line(struct nk_draw_list*, const struct nk_vec2 *pnts, const unsigned int cnt, struct nk_color, enum nk_draw_list_stroke, float thickness, enum nk_anti_aliasing);
2904
2905/* fill */
2906NK_API void nk_draw_list_fill_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding);
2907NK_API void nk_draw_list_fill_rect_multi_color(struct nk_draw_list*, struct nk_rect rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom);
2908NK_API void nk_draw_list_fill_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color);
2909NK_API void nk_draw_list_fill_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color col, unsigned int segs);
2910NK_API void nk_draw_list_fill_poly_convex(struct nk_draw_list*, const struct nk_vec2 *points, const unsigned int count, struct nk_color, enum nk_anti_aliasing);
2911
2912/* misc */
2913NK_API void nk_draw_list_add_image(struct nk_draw_list*, struct nk_image texture, struct nk_rect rect, struct nk_color);
2914NK_API void nk_draw_list_add_text(struct nk_draw_list*, const struct nk_user_font*, struct nk_rect, const char *text, int len, float font_height, struct nk_color);
2915#ifdef NK_INCLUDE_COMMAND_USERDATA
2916NK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata);
2917#endif
2918
2919#endif
2920
2921/* ===============================================================
2922 *
2923 * GUI
2924 *
2925 * ===============================================================*/
2926enum nk_style_item_type {
2927 NK_STYLE_ITEM_COLOR,
2928 NK_STYLE_ITEM_IMAGE
2929};
2930
2931union nk_style_item_data {
2932 struct nk_image image;
2933 struct nk_color color;
2934};
2935
2936struct nk_style_item {
2937 enum nk_style_item_type type;
2938 union nk_style_item_data data;
2939};
2940
2941struct nk_style_text {
2942 struct nk_color color;
2943 struct nk_vec2 padding;
2944};
2945
2946struct nk_style_button {
2947 /* background */
2948 struct nk_style_item normal;
2949 struct nk_style_item hover;
2950 struct nk_style_item active;
2951 struct nk_color border_color;
2952
2953 /* text */
2954 struct nk_color text_background;
2955 struct nk_color text_normal;
2956 struct nk_color text_hover;
2957 struct nk_color text_active;
2958 nk_flags text_alignment;
2959
2960 /* properties */
2961 float border;
2962 float rounding;
2963 struct nk_vec2 padding;
2964 struct nk_vec2 image_padding;
2965 struct nk_vec2 touch_padding;
2966
2967 /* optional user callbacks */
2968 nk_handle userdata;
2969 void(*draw_begin)(struct nk_command_buffer*, nk_handle userdata);
2970 void(*draw_end)(struct nk_command_buffer*, nk_handle userdata);
2971};
2972
2973struct nk_style_toggle {
2974 /* background */
2975 struct nk_style_item normal;
2976 struct nk_style_item hover;
2977 struct nk_style_item active;
2978 struct nk_color border_color;
2979
2980 /* cursor */
2981 struct nk_style_item cursor_normal;
2982 struct nk_style_item cursor_hover;
2983
2984 /* text */
2985 struct nk_color text_normal;
2986 struct nk_color text_hover;
2987 struct nk_color text_active;
2988 struct nk_color text_background;
2989 nk_flags text_alignment;
2990
2991 /* properties */
2992 struct nk_vec2 padding;
2993 struct nk_vec2 touch_padding;
2994 float spacing;
2995 float border;
2996
2997 /* optional user callbacks */
2998 nk_handle userdata;
2999 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3000 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3001};
3002
3003struct nk_style_selectable {
3004 /* background (inactive) */
3005 struct nk_style_item normal;
3006 struct nk_style_item hover;
3007 struct nk_style_item pressed;
3008
3009 /* background (active) */
3010 struct nk_style_item normal_active;
3011 struct nk_style_item hover_active;
3012 struct nk_style_item pressed_active;
3013
3014 /* text color (inactive) */
3015 struct nk_color text_normal;
3016 struct nk_color text_hover;
3017 struct nk_color text_pressed;
3018
3019 /* text color (active) */
3020 struct nk_color text_normal_active;
3021 struct nk_color text_hover_active;
3022 struct nk_color text_pressed_active;
3023 struct nk_color text_background;
3024 nk_flags text_alignment;
3025
3026 /* properties */
3027 float rounding;
3028 struct nk_vec2 padding;
3029 struct nk_vec2 touch_padding;
3030 struct nk_vec2 image_padding;
3031
3032 /* optional user callbacks */
3033 nk_handle userdata;
3034 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3035 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3036};
3037
3038struct nk_style_slider {
3039 /* background */
3040 struct nk_style_item normal;
3041 struct nk_style_item hover;
3042 struct nk_style_item active;
3043 struct nk_color border_color;
3044
3045 /* background bar */
3046 struct nk_color bar_normal;
3047 struct nk_color bar_hover;
3048 struct nk_color bar_active;
3049 struct nk_color bar_filled;
3050
3051 /* cursor */
3052 struct nk_style_item cursor_normal;
3053 struct nk_style_item cursor_hover;
3054 struct nk_style_item cursor_active;
3055
3056 /* properties */
3057 float border;
3058 float rounding;
3059 float bar_height;
3060 struct nk_vec2 padding;
3061 struct nk_vec2 spacing;
3062 struct nk_vec2 cursor_size;
3063
3064 /* optional buttons */
3065 int show_buttons;
3066 struct nk_style_button inc_button;
3067 struct nk_style_button dec_button;
3068 enum nk_symbol_type inc_symbol;
3069 enum nk_symbol_type dec_symbol;
3070
3071 /* optional user callbacks */
3072 nk_handle userdata;
3073 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3074 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3075};
3076
3077struct nk_style_progress {
3078 /* background */
3079 struct nk_style_item normal;
3080 struct nk_style_item hover;
3081 struct nk_style_item active;
3082 struct nk_color border_color;
3083
3084 /* cursor */
3085 struct nk_style_item cursor_normal;
3086 struct nk_style_item cursor_hover;
3087 struct nk_style_item cursor_active;
3088 struct nk_color cursor_border_color;
3089
3090 /* properties */
3091 float rounding;
3092 float border;
3093 float cursor_border;
3094 float cursor_rounding;
3095 struct nk_vec2 padding;
3096
3097 /* optional user callbacks */
3098 nk_handle userdata;
3099 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3100 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3101};
3102
3103struct nk_style_scrollbar {
3104 /* background */
3105 struct nk_style_item normal;
3106 struct nk_style_item hover;
3107 struct nk_style_item active;
3108 struct nk_color border_color;
3109
3110 /* cursor */
3111 struct nk_style_item cursor_normal;
3112 struct nk_style_item cursor_hover;
3113 struct nk_style_item cursor_active;
3114 struct nk_color cursor_border_color;
3115
3116 /* properties */
3117 float border;
3118 float rounding;
3119 float border_cursor;
3120 float rounding_cursor;
3121 struct nk_vec2 padding;
3122
3123 /* optional buttons */
3124 int show_buttons;
3125 struct nk_style_button inc_button;
3126 struct nk_style_button dec_button;
3127 enum nk_symbol_type inc_symbol;
3128 enum nk_symbol_type dec_symbol;
3129
3130 /* optional user callbacks */
3131 nk_handle userdata;
3132 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3133 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3134};
3135
3136struct nk_style_edit {
3137 /* background */
3138 struct nk_style_item normal;
3139 struct nk_style_item hover;
3140 struct nk_style_item active;
3141 struct nk_color border_color;
3142 struct nk_style_scrollbar scrollbar;
3143
3144 /* cursor */
3145 struct nk_color cursor_normal;
3146 struct nk_color cursor_hover;
3147 struct nk_color cursor_text_normal;
3148 struct nk_color cursor_text_hover;
3149
3150 /* text (unselected) */
3151 struct nk_color text_normal;
3152 struct nk_color text_hover;
3153 struct nk_color text_active;
3154
3155 /* text (selected) */
3156 struct nk_color selected_normal;
3157 struct nk_color selected_hover;
3158 struct nk_color selected_text_normal;
3159 struct nk_color selected_text_hover;
3160
3161 /* properties */
3162 float border;
3163 float rounding;
3164 float cursor_size;
3165 struct nk_vec2 scrollbar_size;
3166 struct nk_vec2 padding;
3167 float row_padding;
3168};
3169
3170struct nk_style_property {
3171 /* background */
3172 struct nk_style_item normal;
3173 struct nk_style_item hover;
3174 struct nk_style_item active;
3175 struct nk_color border_color;
3176
3177 /* text */
3178 struct nk_color label_normal;
3179 struct nk_color label_hover;
3180 struct nk_color label_active;
3181
3182 /* symbols */
3183 enum nk_symbol_type sym_left;
3184 enum nk_symbol_type sym_right;
3185
3186 /* properties */
3187 float border;
3188 float rounding;
3189 struct nk_vec2 padding;
3190
3191 struct nk_style_edit edit;
3192 struct nk_style_button inc_button;
3193 struct nk_style_button dec_button;
3194
3195 /* optional user callbacks */
3196 nk_handle userdata;
3197 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3198 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3199};
3200
3201struct nk_style_chart {
3202 /* colors */
3203 struct nk_style_item background;
3204 struct nk_color border_color;
3205 struct nk_color selected_color;
3206 struct nk_color color;
3207
3208 /* properties */
3209 float border;
3210 float rounding;
3211 struct nk_vec2 padding;
3212};
3213
3214struct nk_style_combo {
3215 /* background */
3216 struct nk_style_item normal;
3217 struct nk_style_item hover;
3218 struct nk_style_item active;
3219 struct nk_color border_color;
3220
3221 /* label */
3222 struct nk_color label_normal;
3223 struct nk_color label_hover;
3224 struct nk_color label_active;
3225
3226 /* symbol */
3227 struct nk_color symbol_normal;
3228 struct nk_color symbol_hover;
3229 struct nk_color symbol_active;
3230
3231 /* button */
3232 struct nk_style_button button;
3233 enum nk_symbol_type sym_normal;
3234 enum nk_symbol_type sym_hover;
3235 enum nk_symbol_type sym_active;
3236
3237 /* properties */
3238 float border;
3239 float rounding;
3240 struct nk_vec2 content_padding;
3241 struct nk_vec2 button_padding;
3242 struct nk_vec2 spacing;
3243};
3244
3245struct nk_style_tab {
3246 /* background */
3247 struct nk_style_item background;
3248 struct nk_color border_color;
3249 struct nk_color text;
3250
3251 /* button */
3252 struct nk_style_button tab_maximize_button;
3253 struct nk_style_button tab_minimize_button;
3254 struct nk_style_button node_maximize_button;
3255 struct nk_style_button node_minimize_button;
3256 enum nk_symbol_type sym_minimize;
3257 enum nk_symbol_type sym_maximize;
3258
3259 /* properties */
3260 float border;
3261 float rounding;
3262 float indent;
3263 struct nk_vec2 padding;
3264 struct nk_vec2 spacing;
3265};
3266
3267enum nk_style_header_align {
3268 NK_HEADER_LEFT,
3269 NK_HEADER_RIGHT
3270};
3271struct nk_style_window_header {
3272 /* background */
3273 struct nk_style_item normal;
3274 struct nk_style_item hover;
3275 struct nk_style_item active;
3276
3277 /* button */
3278 struct nk_style_button close_button;
3279 struct nk_style_button minimize_button;
3280 enum nk_symbol_type close_symbol;
3281 enum nk_symbol_type minimize_symbol;
3282 enum nk_symbol_type maximize_symbol;
3283
3284 /* title */
3285 struct nk_color label_normal;
3286 struct nk_color label_hover;
3287 struct nk_color label_active;
3288
3289 /* properties */
3290 enum nk_style_header_align align;
3291 struct nk_vec2 padding;
3292 struct nk_vec2 label_padding;
3293 struct nk_vec2 spacing;
3294};
3295
3296struct nk_style_window {
3297 struct nk_style_window_header header;
3298 struct nk_style_item fixed_background;
3299 struct nk_color background;
3300
3301 struct nk_color border_color;
3302 struct nk_color popup_border_color;
3303 struct nk_color combo_border_color;
3304 struct nk_color contextual_border_color;
3305 struct nk_color menu_border_color;
3306 struct nk_color group_border_color;
3307 struct nk_color tooltip_border_color;
3308 struct nk_style_item scaler;
3309
3310 float border;
3311 float combo_border;
3312 float contextual_border;
3313 float menu_border;
3314 float group_border;
3315 float tooltip_border;
3316 float popup_border;
3317
3318 float rounding;
3319 struct nk_vec2 spacing;
3320 struct nk_vec2 scrollbar_size;
3321 struct nk_vec2 min_size;
3322
3323 struct nk_vec2 padding;
3324 struct nk_vec2 group_padding;
3325 struct nk_vec2 popup_padding;
3326 struct nk_vec2 combo_padding;
3327 struct nk_vec2 contextual_padding;
3328 struct nk_vec2 menu_padding;
3329 struct nk_vec2 tooltip_padding;
3330};
3331
3332struct nk_style {
3333 const struct nk_user_font *font;
3334 const struct nk_cursor *cursors[NK_CURSOR_COUNT];
3335 const struct nk_cursor *cursor_active;
3336 struct nk_cursor *cursor_last;
3337 int cursor_visible;
3338
3339 struct nk_style_text text;
3340 struct nk_style_button button;
3341 struct nk_style_button contextual_button;
3342 struct nk_style_button menu_button;
3343 struct nk_style_toggle option;
3344 struct nk_style_toggle checkbox;
3345 struct nk_style_selectable selectable;
3346 struct nk_style_slider slider;
3347 struct nk_style_progress progress;
3348 struct nk_style_property property;
3349 struct nk_style_edit edit;
3350 struct nk_style_chart chart;
3351 struct nk_style_scrollbar scrollh;
3352 struct nk_style_scrollbar scrollv;
3353 struct nk_style_tab tab;
3354 struct nk_style_combo combo;
3355 struct nk_style_window window;
3356};
3357
3358NK_API struct nk_style_item nk_style_item_image(struct nk_image img);
3359NK_API struct nk_style_item nk_style_item_color(struct nk_color);
3360NK_API struct nk_style_item nk_style_item_hide(void);
3361
3362/*==============================================================
3363 * PANEL
3364 * =============================================================*/
3365#ifndef NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS
3366#define NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS 16
3367#endif
3368#ifndef NK_CHART_MAX_SLOT
3369#define NK_CHART_MAX_SLOT 4
3370#endif
3371
3372enum nk_panel_type {
3373 NK_PANEL_WINDOW = NK_FLAG(0),
3374 NK_PANEL_GROUP = NK_FLAG(1),
3375 NK_PANEL_POPUP = NK_FLAG(2),
3376 NK_PANEL_CONTEXTUAL = NK_FLAG(4),
3377 NK_PANEL_COMBO = NK_FLAG(5),
3378 NK_PANEL_MENU = NK_FLAG(6),
3379 NK_PANEL_TOOLTIP = NK_FLAG(7)
3380};
3381enum nk_panel_set {
3382 NK_PANEL_SET_NONBLOCK = NK_PANEL_CONTEXTUAL|NK_PANEL_COMBO|NK_PANEL_MENU|NK_PANEL_TOOLTIP,
3383 NK_PANEL_SET_POPUP = NK_PANEL_SET_NONBLOCK|NK_PANEL_POPUP,
3384 NK_PANEL_SET_SUB = NK_PANEL_SET_POPUP|NK_PANEL_GROUP
3385};
3386
3387struct nk_chart_slot {
3388 enum nk_chart_type type;
3389 struct nk_color color;
3390 struct nk_color highlight;
3391 float min, max, range;
3392 int count;
3393 struct nk_vec2 last;
3394 int index;
3395};
3396
3397struct nk_chart {
3398 int slot;
3399 float x, y, w, h;
3400 struct nk_chart_slot slots[NK_CHART_MAX_SLOT];
3401};
3402
3403enum nk_panel_row_layout_type {
3404 NK_LAYOUT_DYNAMIC_FIXED = 0,
3405 NK_LAYOUT_DYNAMIC_ROW,
3406 NK_LAYOUT_DYNAMIC_FREE,
3407 NK_LAYOUT_DYNAMIC,
3408 NK_LAYOUT_STATIC_FIXED,
3409 NK_LAYOUT_STATIC_ROW,
3410 NK_LAYOUT_STATIC_FREE,
3411 NK_LAYOUT_STATIC,
3412 NK_LAYOUT_TEMPLATE,
3413 NK_LAYOUT_COUNT
3414};
3415struct nk_row_layout {
3416 enum nk_panel_row_layout_type type;
3417 int index;
3418 float height;
3419 int columns;
3420 const float *ratio;
3421 float item_width;
3422 float item_height;
3423 float item_offset;
3424 float filled;
3425 struct nk_rect item;
3426 int tree_depth;
3427 float templates[NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS];
3428};
3429
3430struct nk_popup_buffer {
3431 nk_size begin;
3432 nk_size parent;
3433 nk_size last;
3434 nk_size end;
3435 int active;
3436};
3437
3438struct nk_menu_state {
3439 float x, y, w, h;
3440 struct nk_scroll offset;
3441};
3442
3443struct nk_panel {
3444 enum nk_panel_type type;
3445 nk_flags flags;
3446 struct nk_rect bounds;
3447 nk_uint *offset_x;
3448 nk_uint *offset_y;
3449 float at_x, at_y, max_x;
3450 float footer_height;
3451 float header_height;
3452 float border;
3453 unsigned int has_scrolling;
3454 struct nk_rect clip;
3455 struct nk_menu_state menu;
3456 struct nk_row_layout row;
3457 struct nk_chart chart;
3458 struct nk_command_buffer *buffer;
3459 struct nk_panel *parent;
3460};
3461
3462/*==============================================================
3463 * WINDOW
3464 * =============================================================*/
3465#ifndef NK_WINDOW_MAX_NAME
3466#define NK_WINDOW_MAX_NAME 64
3467#endif
3468
3469struct nk_table;
3470enum nk_window_flags {
3471 NK_WINDOW_PRIVATE = NK_FLAG(11),
3472 NK_WINDOW_DYNAMIC = NK_WINDOW_PRIVATE,
3473 /* special window type growing up in height while being filled to a certain maximum height */
3474 NK_WINDOW_ROM = NK_FLAG(12),
3475 /* sets window widgets into a read only mode and does not allow input changes */
3476 NK_WINDOW_NOT_INTERACTIVE = NK_WINDOW_ROM|NK_WINDOW_NO_INPUT,
3477 /* prevents all interaction caused by input to either window or widgets inside */
3478 NK_WINDOW_HIDDEN = NK_FLAG(13),
3479 /* Hides window and stops any window interaction and drawing */
3480 NK_WINDOW_CLOSED = NK_FLAG(14),
3481 /* Directly closes and frees the window at the end of the frame */
3482 NK_WINDOW_MINIMIZED = NK_FLAG(15),
3483 /* marks the window as minimized */
3484 NK_WINDOW_REMOVE_ROM = NK_FLAG(16)
3485 /* Removes read only mode at the end of the window */
3486};
3487
3488struct nk_popup_state {
3489 struct nk_window *win;
3490 enum nk_panel_type type;
3491 struct nk_popup_buffer buf;
3492 nk_hash name;
3493 int active;
3494 unsigned combo_count;
3495 unsigned con_count, con_old;
3496 unsigned active_con;
3497 struct nk_rect header;
3498};
3499
3500struct nk_edit_state {
3501 nk_hash name;
3502 unsigned int seq;
3503 unsigned int old;
3504 int active, prev;
3505 int cursor;
3506 int sel_start;
3507 int sel_end;
3508 struct nk_scroll scrollbar;
3509 unsigned char mode;
3510 unsigned char single_line;
3511};
3512
3513struct nk_property_state {
3514 int active, prev;
3515 char buffer[NK_MAX_NUMBER_BUFFER];
3516 int length;
3517 int cursor;
3518 nk_hash name;
3519 unsigned int seq;
3520 unsigned int old;
3521 int state;
3522};
3523
3524struct nk_window {
3525 unsigned int seq;
3526 nk_hash name;
3527 char name_string[NK_WINDOW_MAX_NAME];
3528 nk_flags flags;
3529
3530 struct nk_rect bounds;
3531 struct nk_scroll scrollbar;
3532 struct nk_command_buffer buffer;
3533 struct nk_panel *layout;
3534 float scrollbar_hiding_timer;
3535
3536 /* persistent widget state */
3537 struct nk_property_state property;
3538 struct nk_popup_state popup;
3539 struct nk_edit_state edit;
3540 unsigned int scrolled;
3541
3542 struct nk_table *tables;
3543 unsigned short table_count;
3544 unsigned short table_size;
3545
3546 /* window list hooks */
3547 struct nk_window *next;
3548 struct nk_window *prev;
3549 struct nk_window *parent;
3550};
3551
3552/*==============================================================
3553 * STACK
3554 * =============================================================*/
3555/* The style modifier stack can be used to temporarily change a
3556 * property inside `nk_style`. For example if you want a special
3557 * red button you can temporarily push the old button color onto a stack
3558 * draw the button with a red color and then you just pop the old color
3559 * back from the stack:
3560 *
3561 * nk_style_push_style_item(ctx, &ctx->style.button.normal, nk_style_item_color(nk_rgb(255,0,0)));
3562 * nk_style_push_style_item(ctx, &ctx->style.button.hover, nk_style_item_color(nk_rgb(255,0,0)));
3563 * nk_style_push_style_item(ctx, &ctx->style.button.active, nk_style_item_color(nk_rgb(255,0,0)));
3564 * nk_style_push_vec2(ctx, &cx->style.button.padding, nk_vec2(2,2));
3565 *
3566 * nk_button(...);
3567 *
3568 * nk_style_pop_style_item(ctx);
3569 * nk_style_pop_style_item(ctx);
3570 * nk_style_pop_style_item(ctx);
3571 * nk_style_pop_vec2(ctx);
3572 *
3573 * Nuklear has a stack for style_items, float properties, vector properties,
3574 * flags, colors, fonts and for button_behavior. Each has it's own fixed size stack
3575 * which can be changed at compile time.
3576 */
3577#ifndef NK_BUTTON_BEHAVIOR_STACK_SIZE
3578#define NK_BUTTON_BEHAVIOR_STACK_SIZE 8
3579#endif
3580
3581#ifndef NK_FONT_STACK_SIZE
3582#define NK_FONT_STACK_SIZE 8
3583#endif
3584
3585#ifndef NK_STYLE_ITEM_STACK_SIZE
3586#define NK_STYLE_ITEM_STACK_SIZE 16
3587#endif
3588
3589#ifndef NK_FLOAT_STACK_SIZE
3590#define NK_FLOAT_STACK_SIZE 32
3591#endif
3592
3593#ifndef NK_VECTOR_STACK_SIZE
3594#define NK_VECTOR_STACK_SIZE 16
3595#endif
3596
3597#ifndef NK_FLAGS_STACK_SIZE
3598#define NK_FLAGS_STACK_SIZE 32
3599#endif
3600
3601#ifndef NK_COLOR_STACK_SIZE
3602#define NK_COLOR_STACK_SIZE 32
3603#endif
3604
3605#define NK_CONFIGURATION_STACK_TYPE(prefix, name, type)\
3606 struct nk_config_stack_##name##_element {\
3607 prefix##_##type *address;\
3608 prefix##_##type old_value;\
3609 }
3610#define NK_CONFIG_STACK(type,size)\
3611 struct nk_config_stack_##type {\
3612 int head;\
3613 struct nk_config_stack_##type##_element elements[size];\
3614 }
3615
3616#define nk_float float
3617NK_CONFIGURATION_STACK_TYPE(struct nk, style_item, style_item);
3618NK_CONFIGURATION_STACK_TYPE(nk ,float, float);
3619NK_CONFIGURATION_STACK_TYPE(struct nk, vec2, vec2);
3620NK_CONFIGURATION_STACK_TYPE(nk ,flags, flags);
3621NK_CONFIGURATION_STACK_TYPE(struct nk, color, color);
3622NK_CONFIGURATION_STACK_TYPE(const struct nk, user_font, user_font*);
3623NK_CONFIGURATION_STACK_TYPE(enum nk, button_behavior, button_behavior);
3624
3625NK_CONFIG_STACK(style_item, NK_STYLE_ITEM_STACK_SIZE);
3626NK_CONFIG_STACK(float, NK_FLOAT_STACK_SIZE);
3627NK_CONFIG_STACK(vec2, NK_VECTOR_STACK_SIZE);
3628NK_CONFIG_STACK(flags, NK_FLAGS_STACK_SIZE);
3629NK_CONFIG_STACK(color, NK_COLOR_STACK_SIZE);
3630NK_CONFIG_STACK(user_font, NK_FONT_STACK_SIZE);
3631NK_CONFIG_STACK(button_behavior, NK_BUTTON_BEHAVIOR_STACK_SIZE);
3632
3633struct nk_configuration_stacks {
3634 struct nk_config_stack_style_item style_items;
3635 struct nk_config_stack_float floats;
3636 struct nk_config_stack_vec2 vectors;
3637 struct nk_config_stack_flags flags;
3638 struct nk_config_stack_color colors;
3639 struct nk_config_stack_user_font fonts;
3640 struct nk_config_stack_button_behavior button_behaviors;
3641};
3642
3643/*==============================================================
3644 * CONTEXT
3645 * =============================================================*/
3646#define NK_VALUE_PAGE_CAPACITY \
3647 ((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint)) / 2)
3648
3649struct nk_table {
3650 unsigned int seq;
3651 nk_hash keys[NK_VALUE_PAGE_CAPACITY];
3652 nk_uint values[NK_VALUE_PAGE_CAPACITY];
3653 struct nk_table *next, *prev;
3654};
3655
3656union nk_page_data {
3657 struct nk_table tbl;
3658 struct nk_panel pan;
3659 struct nk_window win;
3660};
3661
3662struct nk_page_element {
3663 union nk_page_data data;
3664 struct nk_page_element *next;
3665 struct nk_page_element *prev;
3666};
3667
3668struct nk_page {
3669 unsigned int size;
3670 struct nk_page *next;
3671 struct nk_page_element win[1];
3672};
3673
3674struct nk_pool {
3675 struct nk_allocator alloc;
3676 enum nk_allocation_type type;
3677 unsigned int page_count;
3678 struct nk_page *pages;
3679 struct nk_page_element *freelist;
3680 unsigned capacity;
3681 nk_size size;
3682 nk_size cap;
3683};
3684
3685struct nk_context {
3686/* public: can be accessed freely */
3687 struct nk_input input;
3688 struct nk_style style;
3689 struct nk_buffer memory;
3690 struct nk_clipboard clip;
3691 nk_flags last_widget_state;
3692 enum nk_button_behavior button_behavior;
3693 struct nk_configuration_stacks stacks;
3694 float delta_time_seconds;
3695
3696/* private:
3697 should only be accessed if you
3698 know what you are doing */
3699#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
3700 struct nk_draw_list draw_list;
3701#endif
3702#ifdef NK_INCLUDE_COMMAND_USERDATA
3703 nk_handle userdata;
3704#endif
3705 /* text editor objects are quite big because of an internal
3706 * undo/redo stack. Therefore it does not make sense to have one for
3707 * each window for temporary use cases, so I only provide *one* instance
3708 * for all windows. This works because the content is cleared anyway */
3709 struct nk_text_edit text_edit;
3710 /* draw buffer used for overlay drawing operation like cursor */
3711 struct nk_command_buffer overlay;
3712
3713 /* windows */
3714 int build;
3715 int use_pool;
3716 struct nk_pool pool;
3717 struct nk_window *begin;
3718 struct nk_window *end;
3719 struct nk_window *active;
3720 struct nk_window *current;
3721 struct nk_page_element *freelist;
3722 unsigned int count;
3723 unsigned int seq;
3724};
3725
3726/* ==============================================================
3727 * MATH
3728 * =============================================================== */
3729#define NK_PI 3.141592654f
3730#define NK_UTF_INVALID 0xFFFD
3731#define NK_MAX_FLOAT_PRECISION 2
3732
3733#define NK_UNUSED(x) ((void)(x))
3734#define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x)))
3735#define NK_LEN(a) (sizeof(a)/sizeof(a)[0])
3736#define NK_ABS(a) (((a) < 0) ? -(a) : (a))
3737#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
3738#define NK_INBOX(px, py, x, y, w, h)\
3739 (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h))
3740#define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \
3741 (!(((x1 > (x0 + w0)) || ((x1 + w1) < x0) || (y1 > (y0 + h0)) || (y1 + h1) < y0)))
3742#define NK_CONTAINS(x, y, w, h, bx, by, bw, bh)\
3743 (NK_INBOX(x,y, bx, by, bw, bh) && NK_INBOX(x+w,y+h, bx, by, bw, bh))
3744
3745#define nk_vec2_sub(a, b) nk_vec2((a).x - (b).x, (a).y - (b).y)
3746#define nk_vec2_add(a, b) nk_vec2((a).x + (b).x, (a).y + (b).y)
3747#define nk_vec2_len_sqr(a) ((a).x*(a).x+(a).y*(a).y)
3748#define nk_vec2_muls(a, t) nk_vec2((a).x * (t), (a).y * (t))
3749
3750#define nk_ptr_add(t, p, i) ((t*)((void*)((nk_byte*)(p) + (i))))
3751#define nk_ptr_add_const(t, p, i) ((const t*)((const void*)((const nk_byte*)(p) + (i))))
3752#define nk_zero_struct(s) nk_zero(&s, sizeof(s))
3753
3754/* ==============================================================
3755 * ALIGNMENT
3756 * =============================================================== */
3757/* Pointer to Integer type conversion for pointer alignment */
3758#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC*/
3759# define NK_UINT_TO_PTR(x) ((void*)(__PTRDIFF_TYPE__)(x))
3760# define NK_PTR_TO_UINT(x) ((nk_size)(__PTRDIFF_TYPE__)(x))
3761#elif !defined(__GNUC__) /* works for compilers other than LLVM */
3762# define NK_UINT_TO_PTR(x) ((void*)&((char*)0)[x])
3763# define NK_PTR_TO_UINT(x) ((nk_size)(((char*)x)-(char*)0))
3764#elif defined(NK_USE_FIXED_TYPES) /* used if we have <stdint.h> */
3765# define NK_UINT_TO_PTR(x) ((void*)(uintptr_t)(x))
3766# define NK_PTR_TO_UINT(x) ((uintptr_t)(x))
3767#else /* generates warning but works */
3768# define NK_UINT_TO_PTR(x) ((void*)(x))
3769# define NK_PTR_TO_UINT(x) ((nk_size)(x))
3770#endif
3771
3772#define NK_ALIGN_PTR(x, mask)\
3773 (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x) + (mask-1)) & ~(mask-1))))
3774#define NK_ALIGN_PTR_BACK(x, mask)\
3775 (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x)) & ~(mask-1))))
3776
3777#define NK_OFFSETOF(st,m) ((nk_ptr)&(((st*)0)->m))
3778#define NK_CONTAINER_OF(ptr,type,member)\
3779 (type*)((void*)((char*)(1 ? (ptr): &((type*)0)->member) - NK_OFFSETOF(type, member)))
3780
3781#ifdef __cplusplus
3782}
3783#endif
3784
3785#ifdef __cplusplus
3786template<typename T> struct nk_alignof;
3787template<typename T, int size_diff> struct nk_helper{enum {value = size_diff};};
3788template<typename T> struct nk_helper<T,0>{enum {value = nk_alignof<T>::value};};
3789template<typename T> struct nk_alignof{struct Big {T x; char c;}; enum {
3790 diff = sizeof(Big) - sizeof(T), value = nk_helper<Big, diff>::value};};
3791#define NK_ALIGNOF(t) (nk_alignof<t>::value);
3792#elif defined(_MSC_VER)
3793#define NK_ALIGNOF(t) (__alignof(t))
3794#else
3795#define NK_ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0)
3796#endif
3797
3798#endif /* NK_H_ */
3799/*
3800 * ==============================================================
3801 *
3802 * IMPLEMENTATION
3803 *
3804 * ===============================================================
3805 */
3806#ifdef NK_IMPLEMENTATION
3807
3808#ifndef NK_POOL_DEFAULT_CAPACITY
3809#define NK_POOL_DEFAULT_CAPACITY 16
3810#endif
3811
3812#ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE
3813#define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024)
3814#endif
3815
3816#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE
3817#define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024)
3818#endif
3819
3820/* standard library headers */
3821#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
3822#include <stdlib.h> /* malloc, free */
3823#endif
3824#ifdef NK_INCLUDE_STANDARD_IO
3825#include <stdio.h> /* fopen, fclose,... */
3826#endif
3827#ifdef NK_INCLUDE_STANDARD_VARARGS
3828#include <stdarg.h> /* valist, va_start, va_end, ... */
3829#endif
3830#ifndef NK_ASSERT
3831#include <assert.h>
3832#define NK_ASSERT(expr) assert(expr)
3833#endif
3834
3835#ifndef NK_MEMSET
3836#define NK_MEMSET nk_memset
3837#endif
3838#ifndef NK_MEMCPY
3839#define NK_MEMCPY nk_memcopy
3840#endif
3841#ifndef NK_SQRT
3842#define NK_SQRT nk_sqrt
3843#endif
3844#ifndef NK_SIN
3845#define NK_SIN nk_sin
3846#endif
3847#ifndef NK_COS
3848#define NK_COS nk_cos
3849#endif
3850#ifndef NK_STRTOD
3851#define NK_STRTOD nk_strtod
3852#endif
3853#ifndef NK_DTOA
3854#define NK_DTOA nk_dtoa
3855#endif
3856
3857#define NK_DEFAULT (-1)
3858
3859#ifndef NK_VSNPRINTF
3860/* If your compiler does support `vsnprintf` I would highly recommend
3861 * defining this to vsnprintf instead since `vsprintf` is basically
3862 * unbelievable unsafe and should *NEVER* be used. But I have to support
3863 * it since C89 only provides this unsafe version. */
3864 #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\
3865 (defined(__cplusplus) && (__cplusplus >= 201103L)) || \
3866 (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\
3867 (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\
3868 defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE)
3869 #define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a)
3870 #else
3871 #define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a)
3872 #endif
3873#endif
3874
3875#define NK_SCHAR_MIN (-127)
3876#define NK_SCHAR_MAX 127
3877#define NK_UCHAR_MIN 0
3878#define NK_UCHAR_MAX 256
3879#define NK_SSHORT_MIN (-32767)
3880#define NK_SSHORT_MAX 32767
3881#define NK_USHORT_MIN 0
3882#define NK_USHORT_MAX 65535
3883#define NK_SINT_MIN (-2147483647)
3884#define NK_SINT_MAX 2147483647
3885#define NK_UINT_MIN 0
3886#define NK_UINT_MAX 4294967295u
3887
3888/* Make sure correct type size:
3889 * This will fire with a negative subscript error if the type sizes
3890 * are set incorrectly by the compiler, and compile out if not */
3891NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));
3892NK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*));
3893NK_STATIC_ASSERT(sizeof(nk_flags) >= 4);
3894NK_STATIC_ASSERT(sizeof(nk_rune) >= 4);
3895NK_STATIC_ASSERT(sizeof(nk_ushort) == 2);
3896NK_STATIC_ASSERT(sizeof(nk_short) == 2);
3897NK_STATIC_ASSERT(sizeof(nk_uint) == 4);
3898NK_STATIC_ASSERT(sizeof(nk_int) == 4);
3899NK_STATIC_ASSERT(sizeof(nk_byte) == 1);
3900
3901NK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384};
3902#define NK_FLOAT_PRECISION 0.00000000000001
3903
3904NK_GLOBAL const struct nk_color nk_red = {255,0,0,255};
3905NK_GLOBAL const struct nk_color nk_green = {0,255,0,255};
3906NK_GLOBAL const struct nk_color nk_blue = {0,0,255,255};
3907NK_GLOBAL const struct nk_color nk_white = {255,255,255,255};
3908NK_GLOBAL const struct nk_color nk_black = {0,0,0,255};
3909NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255};
3910
3911/*
3912 * ==============================================================
3913 *
3914 * MATH
3915 *
3916 * ===============================================================
3917 */
3918/* Since nuklear is supposed to work on all systems providing floating point
3919 math without any dependencies I also had to implement my own math functions
3920 for sqrt, sin and cos. Since the actual highly accurate implementations for
3921 the standard library functions are quite complex and I do not need high
3922 precision for my use cases I use approximations.
3923
3924 Sqrt
3925 ----
3926 For square root nuklear uses the famous fast inverse square root:
3927 https://en.wikipedia.org/wiki/Fast_inverse_square_root with
3928 slightly tweaked magic constant. While on todays hardware it is
3929 probably not faster it is still fast and accurate enough for
3930 nuklear's use cases. IMPORTANT: this requires float format IEEE 754
3931
3932 Sine/Cosine
3933 -----------
3934 All constants inside both function are generated Remez's minimax
3935 approximations for value range 0...2*PI. The reason why I decided to
3936 approximate exactly that range is that nuklear only needs sine and
3937 cosine to generate circles which only requires that exact range.
3938 In addition I used Remez instead of Taylor for additional precision:
3939 www.lolengine.net/blog/2011/12/21/better-function-approximatations.
3940
3941 The tool I used to generate constants for both sine and cosine
3942 (it can actually approximate a lot more functions) can be
3943 found here: www.lolengine.net/wiki/oss/lolremez
3944*/
3945NK_INTERN float
3946nk_inv_sqrt(float number)
3947{
3948 float x2;
3949 const float threehalfs = 1.5f;
3950 union {nk_uint i; float f;} conv = {0};
3951 conv.f = number;
3952 x2 = number * 0.5f;
3953 conv.i = 0x5f375A84 - (conv.i >> 1);
3954 conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f));
3955 return conv.f;
3956}
3957
3958NK_INTERN float
3959nk_sqrt(float x)
3960{
3961 return x * nk_inv_sqrt(x);
3962}
3963
3964NK_INTERN float
3965nk_sin(float x)
3966{
3967 NK_STORAGE const float a0 = +1.91059300966915117e-31f;
3968 NK_STORAGE const float a1 = +1.00086760103908896f;
3969 NK_STORAGE const float a2 = -1.21276126894734565e-2f;
3970 NK_STORAGE const float a3 = -1.38078780785773762e-1f;
3971 NK_STORAGE const float a4 = -2.67353392911981221e-2f;
3972 NK_STORAGE const float a5 = +2.08026600266304389e-2f;
3973 NK_STORAGE const float a6 = -3.03996055049204407e-3f;
3974 NK_STORAGE const float a7 = +1.38235642404333740e-4f;
3975 return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
3976}
3977
3978NK_INTERN float
3979nk_cos(float x)
3980{
3981 NK_STORAGE const float a0 = +1.00238601909309722f;
3982 NK_STORAGE const float a1 = -3.81919947353040024e-2f;
3983 NK_STORAGE const float a2 = -3.94382342128062756e-1f;
3984 NK_STORAGE const float a3 = -1.18134036025221444e-1f;
3985 NK_STORAGE const float a4 = +1.07123798512170878e-1f;
3986 NK_STORAGE const float a5 = -1.86637164165180873e-2f;
3987 NK_STORAGE const float a6 = +9.90140908664079833e-4f;
3988 NK_STORAGE const float a7 = -5.23022132118824778e-14f;
3989 return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
3990}
3991
3992NK_INTERN nk_uint
3993nk_round_up_pow2(nk_uint v)
3994{
3995 v--;
3996 v |= v >> 1;
3997 v |= v >> 2;
3998 v |= v >> 4;
3999 v |= v >> 8;
4000 v |= v >> 16;
4001 v++;
4002 return v;
4003}
4004
4005NK_API struct nk_rect
4006nk_get_null_rect(void)
4007{
4008 return nk_null_rect;
4009}
4010
4011NK_API struct nk_rect
4012nk_rect(float x, float y, float w, float h)
4013{
4014 struct nk_rect r;
4015 r.x = x; r.y = y;
4016 r.w = w; r.h = h;
4017 return r;
4018}
4019
4020NK_API struct nk_rect
4021nk_recti(int x, int y, int w, int h)
4022{
4023 struct nk_rect r;
4024 r.x = (float)x;
4025 r.y = (float)y;
4026 r.w = (float)w;
4027 r.h = (float)h;
4028 return r;
4029}
4030
4031NK_API struct nk_rect
4032nk_recta(struct nk_vec2 pos, struct nk_vec2 size)
4033{
4034 return nk_rect(pos.x, pos.y, size.x, size.y);
4035}
4036
4037NK_API struct nk_rect
4038nk_rectv(const float *r)
4039{
4040 return nk_rect(r[0], r[1], r[2], r[3]);
4041}
4042
4043NK_API struct nk_rect
4044nk_rectiv(const int *r)
4045{
4046 return nk_recti(r[0], r[1], r[2], r[3]);
4047}
4048
4049NK_API struct nk_vec2
4050nk_rect_pos(struct nk_rect r)
4051{
4052 struct nk_vec2 ret;
4053 ret.x = r.x; ret.y = r.y;
4054 return ret;
4055}
4056
4057NK_API struct nk_vec2
4058nk_rect_size(struct nk_rect r)
4059{
4060 struct nk_vec2 ret;
4061 ret.x = r.w; ret.y = r.h;
4062 return ret;
4063}
4064
4065NK_INTERN struct nk_rect
4066nk_shrink_rect(struct nk_rect r, float amount)
4067{
4068 struct nk_rect res;
4069 r.w = NK_MAX(r.w, 2 * amount);
4070 r.h = NK_MAX(r.h, 2 * amount);
4071 res.x = r.x + amount;
4072 res.y = r.y + amount;
4073 res.w = r.w - 2 * amount;
4074 res.h = r.h - 2 * amount;
4075 return res;
4076}
4077
4078NK_INTERN struct nk_rect
4079nk_pad_rect(struct nk_rect r, struct nk_vec2 pad)
4080{
4081 r.w = NK_MAX(r.w, 2 * pad.x);
4082 r.h = NK_MAX(r.h, 2 * pad.y);
4083 r.x += pad.x; r.y += pad.y;
4084 r.w -= 2 * pad.x;
4085 r.h -= 2 * pad.y;
4086 return r;
4087}
4088
4089NK_API struct nk_vec2
4090nk_vec2(float x, float y)
4091{
4092 struct nk_vec2 ret;
4093 ret.x = x; ret.y = y;
4094 return ret;
4095}
4096
4097NK_API struct nk_vec2
4098nk_vec2i(int x, int y)
4099{
4100 struct nk_vec2 ret;
4101 ret.x = (float)x;
4102 ret.y = (float)y;
4103 return ret;
4104}
4105
4106NK_API struct nk_vec2
4107nk_vec2v(const float *v)
4108{
4109 return nk_vec2(v[0], v[1]);
4110}
4111
4112NK_API struct nk_vec2
4113nk_vec2iv(const int *v)
4114{
4115 return nk_vec2i(v[0], v[1]);
4116}
4117
4118/*
4119 * ==============================================================
4120 *
4121 * UTIL
4122 *
4123 * ===============================================================
4124 */
4125NK_INTERN int nk_str_match_here(const char *regexp, const char *text);
4126NK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text);
4127NK_INTERN int nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);}
4128NK_INTERN int nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);}
4129NK_INTERN int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;}
4130NK_INTERN int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;}
4131
4132NK_INTERN void*
4133nk_memcopy(void *dst0, const void *src0, nk_size length)
4134{
4135 nk_ptr t;
4136 char *dst = (char*)dst0;
4137 const char *src = (const char*)src0;
4138 if (length == 0 || dst == src)
4139 goto done;
4140
4141 #define nk_word int
4142 #define nk_wsize sizeof(nk_word)
4143 #define nk_wmask (nk_wsize-1)
4144 #define NK_TLOOP(s) if (t) NK_TLOOP1(s)
4145 #define NK_TLOOP1(s) do { s; } while (--t)
4146
4147 if (dst < src) {
4148 t = (nk_ptr)src; /* only need low bits */
4149 if ((t | (nk_ptr)dst) & nk_wmask) {
4150 if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize)
4151 t = length;
4152 else
4153 t = nk_wsize - (t & nk_wmask);
4154 length -= t;
4155 NK_TLOOP1(*dst++ = *src++);
4156 }
4157 t = length / nk_wsize;
4158 NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src;
4159 src += nk_wsize; dst += nk_wsize);
4160 t = length & nk_wmask;
4161 NK_TLOOP(*dst++ = *src++);
4162 } else {
4163 src += length;
4164 dst += length;
4165 t = (nk_ptr)src;
4166 if ((t | (nk_ptr)dst) & nk_wmask) {
4167 if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize)
4168 t = length;
4169 else
4170 t &= nk_wmask;
4171 length -= t;
4172 NK_TLOOP1(*--dst = *--src);
4173 }
4174 t = length / nk_wsize;
4175 NK_TLOOP(src -= nk_wsize; dst -= nk_wsize;
4176 *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src);
4177 t = length & nk_wmask;
4178 NK_TLOOP(*--dst = *--src);
4179 }
4180 #undef nk_word
4181 #undef nk_wsize
4182 #undef nk_wmask
4183 #undef NK_TLOOP
4184 #undef NK_TLOOP1
4185done:
4186 return (dst0);
4187}
4188
4189NK_INTERN void
4190nk_memset(void *ptr, int c0, nk_size size)
4191{
4192 #define nk_word unsigned
4193 #define nk_wsize sizeof(nk_word)
4194 #define nk_wmask (nk_wsize - 1)
4195 nk_byte *dst = (nk_byte*)ptr;
4196 unsigned c = 0;
4197 nk_size t = 0;
4198
4199 if ((c = (nk_byte)c0) != 0) {
4200 c = (c << 8) | c; /* at least 16-bits */
4201 if (sizeof(unsigned int) > 2)
4202 c = (c << 16) | c; /* at least 32-bits*/
4203 }
4204
4205 /* too small of a word count */
4206 dst = (nk_byte*)ptr;
4207 if (size < 3 * nk_wsize) {
4208 while (size--) *dst++ = (nk_byte)c0;
4209 return;
4210 }
4211
4212 /* align destination */
4213 if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) {
4214 t = nk_wsize -t;
4215 size -= t;
4216 do {
4217 *dst++ = (nk_byte)c0;
4218 } while (--t != 0);
4219 }
4220
4221 /* fill word */
4222 t = size / nk_wsize;
4223 do {
4224 *(nk_word*)((void*)dst) = c;
4225 dst += nk_wsize;
4226 } while (--t != 0);
4227
4228 /* fill trailing bytes */
4229 t = (size & nk_wmask);
4230 if (t != 0) {
4231 do {
4232 *dst++ = (nk_byte)c0;
4233 } while (--t != 0);
4234 }
4235
4236 #undef nk_word
4237 #undef nk_wsize
4238 #undef nk_wmask
4239}
4240
4241NK_INTERN void
4242nk_zero(void *ptr, nk_size size)
4243{
4244 NK_ASSERT(ptr);
4245 NK_MEMSET(ptr, 0, size);
4246}
4247
4248NK_API int
4249nk_strlen(const char *str)
4250{
4251 int siz = 0;
4252 NK_ASSERT(str);
4253 while (str && *str++ != '\0') siz++;
4254 return siz;
4255}
4256
4257NK_API int
4258nk_strtoi(const char *str, const char **endptr)
4259{
4260 int neg = 1;
4261 const char *p = str;
4262 int value = 0;
4263
4264 NK_ASSERT(str);
4265 if (!str) return 0;
4266
4267 /* skip whitespace */
4268 while (*p == ' ') p++;
4269 if (*p == '-') {
4270 neg = -1;
4271 p++;
4272 }
4273 while (*p && *p >= '0' && *p <= '9') {
4274 value = value * 10 + (int) (*p - '0');
4275 p++;
4276 }
4277 if (endptr)
4278 *endptr = p;
4279 return neg*value;
4280}
4281
4282NK_API double
4283nk_strtod(const char *str, const char **endptr)
4284{
4285 double m;
4286 double neg = 1.0;
4287 const char *p = str;
4288 double value = 0;
4289 double number = 0;
4290
4291 NK_ASSERT(str);
4292 if (!str) return 0;
4293
4294 /* skip whitespace */
4295 while (*p == ' ') p++;
4296 if (*p == '-') {
4297 neg = -1.0;
4298 p++;
4299 }
4300
4301 while (*p && *p != '.' && *p != 'e') {
4302 value = value * 10.0 + (double) (*p - '0');
4303 p++;
4304 }
4305
4306 if (*p == '.') {
4307 p++;
4308 for(m = 0.1; *p && *p != 'e'; p++ ) {
4309 value = value + (double) (*p - '0') * m;
4310 m *= 0.1;
4311 }
4312 }
4313 if (*p == 'e') {
4314 int i, pow, div;
4315 p++;
4316 if (*p == '-') {
4317 div = nk_true;
4318 p++;
4319 } else if (*p == '+') {
4320 div = nk_false;
4321 p++;
4322 } else div = nk_false;
4323
4324 for (pow = 0; *p; p++)
4325 pow = pow * 10 + (int) (*p - '0');
4326
4327 for (m = 1.0, i = 0; i < pow; i++)
4328 m *= 10.0;
4329
4330 if (div)
4331 value /= m;
4332 else value *= m;
4333 }
4334 number = value * neg;
4335 if (endptr)
4336 *endptr = p;
4337 return number;
4338}
4339
4340NK_API float
4341nk_strtof(const char *str, const char **endptr)
4342{
4343 float float_value;
4344 double double_value;
4345 double_value = NK_STRTOD(str, endptr);
4346 float_value = (float)double_value;
4347 return float_value;
4348}
4349
4350NK_API int
4351nk_stricmp(const char *s1, const char *s2)
4352{
4353 nk_int c1,c2,d;
4354 do {
4355 c1 = *s1++;
4356 c2 = *s2++;
4357 d = c1 - c2;
4358 while (d) {
4359 if (c1 <= 'Z' && c1 >= 'A') {
4360 d += ('a' - 'A');
4361 if (!d) break;
4362 }
4363 if (c2 <= 'Z' && c2 >= 'A') {
4364 d -= ('a' - 'A');
4365 if (!d) break;
4366 }
4367 return ((d >= 0) << 1) - 1;
4368 }
4369 } while (c1);
4370 return 0;
4371}
4372
4373NK_API int
4374nk_stricmpn(const char *s1, const char *s2, int n)
4375{
4376 int c1,c2,d;
4377 NK_ASSERT(n >= 0);
4378 do {
4379 c1 = *s1++;
4380 c2 = *s2++;
4381 if (!n--) return 0;
4382
4383 d = c1 - c2;
4384 while (d) {
4385 if (c1 <= 'Z' && c1 >= 'A') {
4386 d += ('a' - 'A');
4387 if (!d) break;
4388 }
4389 if (c2 <= 'Z' && c2 >= 'A') {
4390 d -= ('a' - 'A');
4391 if (!d) break;
4392 }
4393 return ((d >= 0) << 1) - 1;
4394 }
4395 } while (c1);
4396 return 0;
4397}
4398
4399NK_INTERN int
4400nk_str_match_here(const char *regexp, const char *text)
4401{
4402 if (regexp[0] == '\0')
4403 return 1;
4404 if (regexp[1] == '*')
4405 return nk_str_match_star(regexp[0], regexp+2, text);
4406 if (regexp[0] == '$' && regexp[1] == '\0')
4407 return *text == '\0';
4408 if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text))
4409 return nk_str_match_here(regexp+1, text+1);
4410 return 0;
4411}
4412
4413NK_INTERN int
4414nk_str_match_star(int c, const char *regexp, const char *text)
4415{
4416 do {/* a '* matches zero or more instances */
4417 if (nk_str_match_here(regexp, text))
4418 return 1;
4419 } while (*text != '\0' && (*text++ == c || c == '.'));
4420 return 0;
4421}
4422
4423NK_API int
4424nk_strfilter(const char *text, const char *regexp)
4425{
4426 /*
4427 c matches any literal character c
4428 . matches any single character
4429 ^ matches the beginning of the input string
4430 $ matches the end of the input string
4431 * matches zero or more occurrences of the previous character*/
4432 if (regexp[0] == '^')
4433 return nk_str_match_here(regexp+1, text);
4434 do { /* must look even if string is empty */
4435 if (nk_str_match_here(regexp, text))
4436 return 1;
4437 } while (*text++ != '\0');
4438 return 0;
4439}
4440
4441NK_API int
4442nk_strmatch_fuzzy_text(const char *str, int str_len,
4443 const char *pattern, int *out_score)
4444{
4445 /* Returns true if each character in pattern is found sequentially within str
4446 * if found then outScore is also set. Score value has no intrinsic meaning.
4447 * Range varies with pattern. Can only compare scores with same search pattern. */
4448
4449 /* ------- scores --------- */
4450 /* bonus for adjacent matches */
4451 #define NK_ADJACENCY_BONUS 5
4452 /* bonus if match occurs after a separator */
4453 #define NK_SEPARATOR_BONUS 10
4454 /* bonus if match is uppercase and prev is lower */
4455 #define NK_CAMEL_BONUS 10
4456 /* penalty applied for every letter in str before the first match */
4457 #define NK_LEADING_LETTER_PENALTY (-3)
4458 /* maximum penalty for leading letters */
4459 #define NK_MAX_LEADING_LETTER_PENALTY (-9)
4460 /* penalty for every letter that doesn't matter */
4461 #define NK_UNMATCHED_LETTER_PENALTY (-1)
4462
4463 /* loop variables */
4464 int score = 0;
4465 char const * pattern_iter = pattern;
4466 int str_iter = 0;
4467 int prev_matched = nk_false;
4468 int prev_lower = nk_false;
4469 /* true so if first letter match gets separator bonus*/
4470 int prev_separator = nk_true;
4471
4472 /* use "best" matched letter if multiple string letters match the pattern */
4473 char const * best_letter = 0;
4474 int best_letter_score = 0;
4475
4476 /* loop over strings */
4477 NK_ASSERT(str);
4478 NK_ASSERT(pattern);
4479 if (!str || !str_len || !pattern) return 0;
4480 while (str_iter < str_len)
4481 {
4482 const char pattern_letter = *pattern_iter;
4483 const char str_letter = str[str_iter];
4484
4485 int next_match = *pattern_iter != '\0' &&
4486 nk_to_lower(pattern_letter) == nk_to_lower(str_letter);
4487 int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter);
4488
4489 int advanced = next_match && best_letter;
4490 int pattern_repeat = best_letter && *pattern_iter != '\0';
4491 pattern_repeat = pattern_repeat &&
4492 nk_to_lower(*best_letter) == nk_to_lower(pattern_letter);
4493
4494 if (advanced || pattern_repeat) {
4495 score += best_letter_score;
4496 best_letter = 0;
4497 best_letter_score = 0;
4498 }
4499
4500 if (next_match || rematch)
4501 {
4502 int new_score = 0;
4503 /* Apply penalty for each letter before the first pattern match */
4504 if (pattern_iter == pattern) {
4505 int count = (int)(&str[str_iter] - str);
4506 int penalty = NK_LEADING_LETTER_PENALTY * count;
4507 if (penalty < NK_MAX_LEADING_LETTER_PENALTY)
4508 penalty = NK_MAX_LEADING_LETTER_PENALTY;
4509
4510 score += penalty;
4511 }
4512
4513 /* apply bonus for consecutive bonuses */
4514 if (prev_matched)
4515 new_score += NK_ADJACENCY_BONUS;
4516
4517 /* apply bonus for matches after a separator */
4518 if (prev_separator)
4519 new_score += NK_SEPARATOR_BONUS;
4520
4521 /* apply bonus across camel case boundaries */
4522 if (prev_lower && nk_is_upper(str_letter))
4523 new_score += NK_CAMEL_BONUS;
4524
4525 /* update pattern iter IFF the next pattern letter was matched */
4526 if (next_match)
4527 ++pattern_iter;
4528
4529 /* update best letter in str which may be for a "next" letter or a rematch */
4530 if (new_score >= best_letter_score) {
4531 /* apply penalty for now skipped letter */
4532 if (best_letter != 0)
4533 score += NK_UNMATCHED_LETTER_PENALTY;
4534
4535 best_letter = &str[str_iter];
4536 best_letter_score = new_score;
4537 }
4538 prev_matched = nk_true;
4539 } else {
4540 score += NK_UNMATCHED_LETTER_PENALTY;
4541 prev_matched = nk_false;
4542 }
4543
4544 /* separators should be more easily defined */
4545 prev_lower = nk_is_lower(str_letter) != 0;
4546 prev_separator = str_letter == '_' || str_letter == ' ';
4547
4548 ++str_iter;
4549 }
4550
4551 /* apply score for last match */
4552 if (best_letter)
4553 score += best_letter_score;
4554
4555 /* did not match full pattern */
4556 if (*pattern_iter != '\0')
4557 return nk_false;
4558
4559 if (out_score)
4560 *out_score = score;
4561 return nk_true;
4562}
4563
4564NK_API int
4565nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score)
4566{return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);}
4567
4568NK_INTERN int
4569nk_string_float_limit(char *string, int prec)
4570{
4571 int dot = 0;
4572 char *c = string;
4573 while (*c) {
4574 if (*c == '.') {
4575 dot = 1;
4576 c++;
4577 continue;
4578 }
4579 if (dot == (prec+1)) {
4580 *c = 0;
4581 break;
4582 }
4583 if (dot > 0) dot++;
4584 c++;
4585 }
4586 return (int)(c - string);
4587}
4588
4589NK_INTERN double
4590nk_pow(double x, int n)
4591{
4592 /* check the sign of n */
4593 double r = 1;
4594 int plus = n >= 0;
4595 n = (plus) ? n : -n;
4596 while (n > 0) {
4597 if ((n & 1) == 1)
4598 r *= x;
4599 n /= 2;
4600 x *= x;
4601 }
4602 return plus ? r : 1.0 / r;
4603}
4604
4605NK_INTERN int
4606nk_ifloord(double x)
4607{
4608 x = (double)((int)x - ((x < 0.0) ? 1 : 0));
4609 return (int)x;
4610}
4611
4612NK_INTERN int
4613nk_ifloorf(float x)
4614{
4615 x = (float)((int)x - ((x < 0.0f) ? 1 : 0));
4616 return (int)x;
4617}
4618
4619NK_INTERN int
4620nk_iceilf(float x)
4621{
4622 if (x >= 0) {
4623 int i = (int)x;
4624 return i;
4625 } else {
4626 int t = (int)x;
4627 float r = x - (float)t;
4628 return (r > 0.0f) ? t+1: t;
4629 }
4630}
4631
4632NK_INTERN int
4633nk_log10(double n)
4634{
4635 int neg;
4636 int ret;
4637 int exp = 0;
4638
4639 neg = (n < 0) ? 1 : 0;
4640 ret = (neg) ? (int)-n : (int)n;
4641 while ((ret / 10) > 0) {
4642 ret /= 10;
4643 exp++;
4644 }
4645 if (neg) exp = -exp;
4646 return exp;
4647}
4648
4649NK_INTERN void
4650nk_strrev_ascii(char *s)
4651{
4652 int len = nk_strlen(s);
4653 int end = len / 2;
4654 int i = 0;
4655 char t;
4656 for (; i < end; ++i) {
4657 t = s[i];
4658 s[i] = s[len - 1 - i];
4659 s[len -1 - i] = t;
4660 }
4661}
4662
4663NK_INTERN char*
4664nk_itoa(char *s, long n)
4665{
4666 long i = 0;
4667 if (n == 0) {
4668 s[i++] = '0';
4669 s[i] = 0;
4670 return s;
4671 }
4672 if (n < 0) {
4673 s[i++] = '-';
4674 n = -n;
4675 }
4676 while (n > 0) {
4677 s[i++] = (char)('0' + (n % 10));
4678 n /= 10;
4679 }
4680 s[i] = 0;
4681 if (s[0] == '-')
4682 ++s;
4683
4684 nk_strrev_ascii(s);
4685 return s;
4686}
4687
4688NK_INTERN char*
4689nk_dtoa(char *s, double n)
4690{
4691 int useExp = 0;
4692 int digit = 0, m = 0, m1 = 0;
4693 char *c = s;
4694 int neg = 0;
4695
4696 NK_ASSERT(s);
4697 if (!s) return 0;
4698
4699 if (n == 0.0) {
4700 s[0] = '0'; s[1] = '\0';
4701 return s;
4702 }
4703
4704 neg = (n < 0);
4705 if (neg) n = -n;
4706
4707 /* calculate magnitude */
4708 m = nk_log10(n);
4709 useExp = (m >= 14 || (neg && m >= 9) || m <= -9);
4710 if (neg) *(c++) = '-';
4711
4712 /* set up for scientific notation */
4713 if (useExp) {
4714 if (m < 0)
4715 m -= 1;
4716 n = n / (double)nk_pow(10.0, m);
4717 m1 = m;
4718 m = 0;
4719 }
4720 if (m < 1.0) {
4721 m = 0;
4722 }
4723
4724 /* convert the number */
4725 while (n > NK_FLOAT_PRECISION || m >= 0) {
4726 double weight = nk_pow(10.0, m);
4727 if (weight > 0) {
4728 double t = (double)n / weight;
4729 digit = nk_ifloord(t);
4730 n -= ((double)digit * weight);
4731 *(c++) = (char)('0' + (char)digit);
4732 }
4733 if (m == 0 && n > 0)
4734 *(c++) = '.';
4735 m--;
4736 }
4737
4738 if (useExp) {
4739 /* convert the exponent */
4740 int i, j;
4741 *(c++) = 'e';
4742 if (m1 > 0) {
4743 *(c++) = '+';
4744 } else {
4745 *(c++) = '-';
4746 m1 = -m1;
4747 }
4748 m = 0;
4749 while (m1 > 0) {
4750 *(c++) = (char)('0' + (char)(m1 % 10));
4751 m1 /= 10;
4752 m++;
4753 }
4754 c -= m;
4755 for (i = 0, j = m-1; i<j; i++, j--) {
4756 /* swap without temporary */
4757 c[i] ^= c[j];
4758 c[j] ^= c[i];
4759 c[i] ^= c[j];
4760 }
4761 c += m;
4762 }
4763 *(c) = '\0';
4764 return s;
4765}
4766
4767#ifdef NK_INCLUDE_STANDARD_VARARGS
4768static int
4769nk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args)
4770{
4771 enum nk_arg_type {
4772 NK_ARG_TYPE_CHAR,
4773 NK_ARG_TYPE_SHORT,
4774 NK_ARG_TYPE_DEFAULT,
4775 NK_ARG_TYPE_LONG
4776 };
4777 enum nk_arg_flags {
4778 NK_ARG_FLAG_LEFT = 0x01,
4779 NK_ARG_FLAG_PLUS = 0x02,
4780 NK_ARG_FLAG_SPACE = 0x04,
4781 NK_ARG_FLAG_NUM = 0x10,
4782 NK_ARG_FLAG_ZERO = 0x20
4783 };
4784
4785 char number_buffer[NK_MAX_NUMBER_BUFFER];
4786 enum nk_arg_type arg_type = NK_ARG_TYPE_DEFAULT;
4787 int precision = NK_DEFAULT;
4788 int width = NK_DEFAULT;
4789 nk_flags flag = 0;
4790
4791 int len = 0;
4792 int result = -1;
4793 const char *iter = fmt;
4794
4795 NK_ASSERT(buf);
4796 NK_ASSERT(buf_size);
4797 if (!buf || !buf_size || !fmt) return 0;
4798 for (iter = fmt; *iter && len < buf_size; iter++) {
4799 /* copy all non-format characters */
4800 while (*iter && (*iter != '%') && (len < buf_size))
4801 buf[len++] = *iter++;
4802 if (!(*iter) || len >= buf_size) break;
4803 iter++;
4804
4805 /* flag arguments */
4806 while (*iter) {
4807 if (*iter == '-') flag |= NK_ARG_FLAG_LEFT;
4808 else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS;
4809 else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE;
4810 else if (*iter == '#') flag |= NK_ARG_FLAG_NUM;
4811 else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO;
4812 else break;
4813 iter++;
4814 }
4815
4816 /* width argument */
4817 width = NK_DEFAULT;
4818 if (*iter >= '1' && *iter <= '9') {
4819 const char *end;
4820 width = nk_strtoi(iter, &end);
4821 if (end == iter)
4822 width = -1;
4823 else iter = end;
4824 } else if (*iter == '*') {
4825 width = va_arg(args, int);
4826 iter++;
4827 }
4828
4829 /* precision argument */
4830 precision = NK_DEFAULT;
4831 if (*iter == '.') {
4832 iter++;
4833 if (*iter == '*') {
4834 precision = va_arg(args, int);
4835 iter++;
4836 } else {
4837 const char *end;
4838 precision = nk_strtoi(iter, &end);
4839 if (end == iter)
4840 precision = -1;
4841 else iter = end;
4842 }
4843 }
4844
4845 /* length modifier */
4846 if (*iter == 'h') {
4847 if (*(iter+1) == 'h') {
4848 arg_type = NK_ARG_TYPE_CHAR;
4849 iter++;
4850 } else arg_type = NK_ARG_TYPE_SHORT;
4851 iter++;
4852 } else if (*iter == 'l') {
4853 arg_type = NK_ARG_TYPE_LONG;
4854 iter++;
4855 } else arg_type = NK_ARG_TYPE_DEFAULT;
4856
4857 /* specifier */
4858 if (*iter == '%') {
4859 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
4860 NK_ASSERT(precision == NK_DEFAULT);
4861 NK_ASSERT(width == NK_DEFAULT);
4862 if (len < buf_size)
4863 buf[len++] = '%';
4864 } else if (*iter == 's') {
4865 /* string */
4866 const char *str = va_arg(args, const char*);
4867 NK_ASSERT(str != buf && "buffer and argument are not allowed to overlap!");
4868 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
4869 NK_ASSERT(precision == NK_DEFAULT);
4870 NK_ASSERT(width == NK_DEFAULT);
4871 if (str == buf) return -1;
4872 while (str && *str && len < buf_size)
4873 buf[len++] = *str++;
4874 } else if (*iter == 'n') {
4875 /* current length callback */
4876 signed int *n = va_arg(args, int*);
4877 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
4878 NK_ASSERT(precision == NK_DEFAULT);
4879 NK_ASSERT(width == NK_DEFAULT);
4880 if (n) *n = len;
4881 } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') {
4882 /* signed integer */
4883 long value = 0;
4884 const char *num_iter;
4885 int num_len, num_print, padding;
4886 int cur_precision = NK_MAX(precision, 1);
4887 int cur_width = NK_MAX(width, 0);
4888
4889 /* retrieve correct value type */
4890 if (arg_type == NK_ARG_TYPE_CHAR)
4891 value = (signed char)va_arg(args, int);
4892 else if (arg_type == NK_ARG_TYPE_SHORT)
4893 value = (signed short)va_arg(args, int);
4894 else if (arg_type == NK_ARG_TYPE_LONG)
4895 value = va_arg(args, signed long);
4896 else if (*iter == 'c')
4897 value = (unsigned char)va_arg(args, int);
4898 else value = va_arg(args, signed int);
4899
4900 /* convert number to string */
4901 nk_itoa(number_buffer, value);
4902 num_len = nk_strlen(number_buffer);
4903 padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);
4904 if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))
4905 padding = NK_MAX(padding-1, 0);
4906
4907 /* fill left padding up to a total of `width` characters */
4908 if (!(flag & NK_ARG_FLAG_LEFT)) {
4909 while (padding-- > 0 && (len < buf_size)) {
4910 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
4911 buf[len++] = '0';
4912 else buf[len++] = ' ';
4913 }
4914 }
4915
4916 /* copy string value representation into buffer */
4917 if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size)
4918 buf[len++] = '+';
4919 else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size)
4920 buf[len++] = ' ';
4921
4922 /* fill up to precision number of digits with '0' */
4923 num_print = NK_MAX(cur_precision, num_len);
4924 while (precision && (num_print > num_len) && (len < buf_size)) {
4925 buf[len++] = '0';
4926 num_print--;
4927 }
4928
4929 /* copy string value representation into buffer */
4930 num_iter = number_buffer;
4931 while (precision && *num_iter && len < buf_size)
4932 buf[len++] = *num_iter++;
4933
4934 /* fill right padding up to width characters */
4935 if (flag & NK_ARG_FLAG_LEFT) {
4936 while ((padding-- > 0) && (len < buf_size))
4937 buf[len++] = ' ';
4938 }
4939 } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') {
4940 /* unsigned integer */
4941 unsigned long value = 0;
4942 int num_len = 0, num_print, padding = 0;
4943 int cur_precision = NK_MAX(precision, 1);
4944 int cur_width = NK_MAX(width, 0);
4945 unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16;
4946
4947 /* print oct/hex/dec value */
4948 const char *upper_output_format = "0123456789ABCDEF";
4949 const char *lower_output_format = "0123456789abcdef";
4950 const char *output_format = (*iter == 'x') ?
4951 lower_output_format: upper_output_format;
4952
4953 /* retrieve correct value type */
4954 if (arg_type == NK_ARG_TYPE_CHAR)
4955 value = (unsigned char)va_arg(args, int);
4956 else if (arg_type == NK_ARG_TYPE_SHORT)
4957 value = (unsigned short)va_arg(args, int);
4958 else if (arg_type == NK_ARG_TYPE_LONG)
4959 value = va_arg(args, unsigned long);
4960 else value = va_arg(args, unsigned int);
4961
4962 do {
4963 /* convert decimal number into hex/oct number */
4964 int digit = output_format[value % base];
4965 if (num_len < NK_MAX_NUMBER_BUFFER)
4966 number_buffer[num_len++] = (char)digit;
4967 value /= base;
4968 } while (value > 0);
4969
4970 num_print = NK_MAX(cur_precision, num_len);
4971 padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);
4972 if (flag & NK_ARG_FLAG_NUM)
4973 padding = NK_MAX(padding-1, 0);
4974
4975 /* fill left padding up to a total of `width` characters */
4976 if (!(flag & NK_ARG_FLAG_LEFT)) {
4977 while ((padding-- > 0) && (len < buf_size)) {
4978 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
4979 buf[len++] = '0';
4980 else buf[len++] = ' ';
4981 }
4982 }
4983
4984 /* fill up to precision number of digits */
4985 if (num_print && (flag & NK_ARG_FLAG_NUM)) {
4986 if ((*iter == 'o') && (len < buf_size)) {
4987 buf[len++] = '0';
4988 } else if ((*iter == 'x') && ((len+1) < buf_size)) {
4989 buf[len++] = '0';
4990 buf[len++] = 'x';
4991 } else if ((*iter == 'X') && ((len+1) < buf_size)) {
4992 buf[len++] = '0';
4993 buf[len++] = 'X';
4994 }
4995 }
4996 while (precision && (num_print > num_len) && (len < buf_size)) {
4997 buf[len++] = '0';
4998 num_print--;
4999 }
5000
5001 /* reverse number direction */
5002 while (num_len > 0) {
5003 if (precision && (len < buf_size))
5004 buf[len++] = number_buffer[num_len-1];
5005 num_len--;
5006 }
5007
5008 /* fill right padding up to width characters */
5009 if (flag & NK_ARG_FLAG_LEFT) {
5010 while ((padding-- > 0) && (len < buf_size))
5011 buf[len++] = ' ';
5012 }
5013 } else if (*iter == 'f') {
5014 /* floating point */
5015 const char *num_iter;
5016 int cur_precision = (precision < 0) ? 6: precision;
5017 int prefix, cur_width = NK_MAX(width, 0);
5018 double value = va_arg(args, double);
5019 int num_len = 0, frac_len = 0, dot = 0;
5020 int padding = 0;
5021
5022 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
5023 NK_DTOA(number_buffer, value);
5024 num_len = nk_strlen(number_buffer);
5025
5026 /* calculate padding */
5027 num_iter = number_buffer;
5028 while (*num_iter && *num_iter != '.')
5029 num_iter++;
5030
5031 prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0;
5032 padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0);
5033 if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))
5034 padding = NK_MAX(padding-1, 0);
5035
5036 /* fill left padding up to a total of `width` characters */
5037 if (!(flag & NK_ARG_FLAG_LEFT)) {
5038 while (padding-- > 0 && (len < buf_size)) {
5039 if (flag & NK_ARG_FLAG_ZERO)
5040 buf[len++] = '0';
5041 else buf[len++] = ' ';
5042 }
5043 }
5044
5045 /* copy string value representation into buffer */
5046 num_iter = number_buffer;
5047 if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size))
5048 buf[len++] = '+';
5049 else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size))
5050 buf[len++] = ' ';
5051 while (*num_iter) {
5052 if (dot) frac_len++;
5053 if (len < buf_size)
5054 buf[len++] = *num_iter;
5055 if (*num_iter == '.') dot = 1;
5056 if (frac_len >= cur_precision) break;
5057 num_iter++;
5058 }
5059
5060 /* fill number up to precision */
5061 while (frac_len < cur_precision) {
5062 if (!dot && len < buf_size) {
5063 buf[len++] = '.';
5064 dot = 1;
5065 }
5066 if (len < buf_size)
5067 buf[len++] = '0';
5068 frac_len++;
5069 }
5070
5071 /* fill right padding up to width characters */
5072 if (flag & NK_ARG_FLAG_LEFT) {
5073 while ((padding-- > 0) && (len < buf_size))
5074 buf[len++] = ' ';
5075 }
5076 } else {
5077 /* Specifier not supported: g,G,e,E,p,z */
5078 NK_ASSERT(0 && "specifier is not supported!");
5079 return result;
5080 }
5081 }
5082 buf[(len >= buf_size)?(buf_size-1):len] = 0;
5083 result = (len >= buf_size)?-1:len;
5084 return result;
5085}
5086
5087NK_INTERN int
5088nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args)
5089{
5090 int result = -1;
5091 NK_ASSERT(buf);
5092 NK_ASSERT(buf_size);
5093 if (!buf || !buf_size || !fmt) return 0;
5094#ifdef NK_INCLUDE_STANDARD_IO
5095 result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args);
5096 result = (result >= buf_size) ? -1: result;
5097 buf[buf_size-1] = 0;
5098#else
5099 result = nk_vsnprintf(buf, buf_size, fmt, args);
5100#endif
5101 return result;
5102}
5103#endif
5104
5105NK_API nk_hash
5106nk_murmur_hash(const void * key, int len, nk_hash seed)
5107{
5108 /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/
5109 #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r)))
5110 union {const nk_uint *i; const nk_byte *b;} conv = {0};
5111 const nk_byte *data = (const nk_byte*)key;
5112 const int nblocks = len/4;
5113 nk_uint h1 = seed;
5114 const nk_uint c1 = 0xcc9e2d51;
5115 const nk_uint c2 = 0x1b873593;
5116 const nk_byte *tail;
5117 const nk_uint *blocks;
5118 nk_uint k1;
5119 int i;
5120
5121 /* body */
5122 if (!key) return 0;
5123 conv.b = (data + nblocks*4);
5124 blocks = (const nk_uint*)conv.i;
5125 for (i = -nblocks; i; ++i) {
5126 k1 = blocks[i];
5127 k1 *= c1;
5128 k1 = NK_ROTL(k1,15);
5129 k1 *= c2;
5130
5131 h1 ^= k1;
5132 h1 = NK_ROTL(h1,13);
5133 h1 = h1*5+0xe6546b64;
5134 }
5135
5136 /* tail */
5137 tail = (const nk_byte*)(data + nblocks*4);
5138 k1 = 0;
5139 switch (len & 3) {
5140 case 3: k1 ^= (nk_uint)(tail[2] << 16);
5141 case 2: k1 ^= (nk_uint)(tail[1] << 8u);
5142 case 1: k1 ^= tail[0];
5143 k1 *= c1;
5144 k1 = NK_ROTL(k1,15);
5145 k1 *= c2;
5146 h1 ^= k1;
5147 default: break;
5148 }
5149
5150 /* finalization */
5151 h1 ^= (nk_uint)len;
5152 /* fmix32 */
5153 h1 ^= h1 >> 16;
5154 h1 *= 0x85ebca6b;
5155 h1 ^= h1 >> 13;
5156 h1 *= 0xc2b2ae35;
5157 h1 ^= h1 >> 16;
5158
5159 #undef NK_ROTL
5160 return h1;
5161}
5162
5163#ifdef NK_INCLUDE_STANDARD_IO
5164NK_INTERN char*
5165nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc)
5166{
5167 char *buf;
5168 FILE *fd;
5169 long ret;
5170
5171 NK_ASSERT(path);
5172 NK_ASSERT(siz);
5173 NK_ASSERT(alloc);
5174 if (!path || !siz || !alloc)
5175 return 0;
5176
5177 fd = fopen(path, "rb");
5178 if (!fd) return 0;
5179 fseek(fd, 0, SEEK_END);
5180 ret = ftell(fd);
5181 if (ret < 0) {
5182 fclose(fd);
5183 return 0;
5184 }
5185 *siz = (nk_size)ret;
5186 fseek(fd, 0, SEEK_SET);
5187 buf = (char*)alloc->alloc(alloc->userdata,0, *siz);
5188 NK_ASSERT(buf);
5189 if (!buf) {
5190 fclose(fd);
5191 return 0;
5192 }
5193 *siz = (nk_size)fread(buf, *siz, 1, fd);
5194 fclose(fd);
5195 return buf;
5196}
5197#endif
5198
5199/*
5200 * ==============================================================
5201 *
5202 * COLOR
5203 *
5204 * ===============================================================
5205 */
5206NK_INTERN int
5207nk_parse_hex(const char *p, int length)
5208{
5209 int i = 0;
5210 int len = 0;
5211 while (len < length) {
5212 i <<= 4;
5213 if (p[len] >= 'a' && p[len] <= 'f')
5214 i += ((p[len] - 'a') + 10);
5215 else if (p[len] >= 'A' && p[len] <= 'F')
5216 i += ((p[len] - 'A') + 10);
5217 else i += (p[len] - '0');
5218 len++;
5219 }
5220 return i;
5221}
5222
5223NK_API struct nk_color
5224nk_rgba(int r, int g, int b, int a)
5225{
5226 struct nk_color ret;
5227 ret.r = (nk_byte)NK_CLAMP(0, r, 255);
5228 ret.g = (nk_byte)NK_CLAMP(0, g, 255);
5229 ret.b = (nk_byte)NK_CLAMP(0, b, 255);
5230 ret.a = (nk_byte)NK_CLAMP(0, a, 255);
5231 return ret;
5232}
5233
5234NK_API struct nk_color
5235nk_rgb_hex(const char *rgb)
5236{
5237 struct nk_color col;
5238 const char *c = rgb;
5239 if (*c == '#') c++;
5240 col.r = (nk_byte)nk_parse_hex(c, 2);
5241 col.g = (nk_byte)nk_parse_hex(c+2, 2);
5242 col.b = (nk_byte)nk_parse_hex(c+4, 2);
5243 col.a = 255;
5244 return col;
5245}
5246
5247NK_API struct nk_color
5248nk_rgba_hex(const char *rgb)
5249{
5250 struct nk_color col;
5251 const char *c = rgb;
5252 if (*c == '#') c++;
5253 col.r = (nk_byte)nk_parse_hex(c, 2);
5254 col.g = (nk_byte)nk_parse_hex(c+2, 2);
5255 col.b = (nk_byte)nk_parse_hex(c+4, 2);
5256 col.a = (nk_byte)nk_parse_hex(c+6, 2);
5257 return col;
5258}
5259
5260NK_API void
5261nk_color_hex_rgba(char *output, struct nk_color col)
5262{
5263 #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))
5264 output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
5265 output[1] = (char)NK_TO_HEX((col.r & 0x0F));
5266 output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
5267 output[3] = (char)NK_TO_HEX((col.g & 0x0F));
5268 output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
5269 output[5] = (char)NK_TO_HEX((col.b & 0x0F));
5270 output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4);
5271 output[7] = (char)NK_TO_HEX((col.a & 0x0F));
5272 output[8] = '\0';
5273 #undef NK_TO_HEX
5274}
5275
5276NK_API void
5277nk_color_hex_rgb(char *output, struct nk_color col)
5278{
5279 #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))
5280 output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
5281 output[1] = (char)NK_TO_HEX((col.r & 0x0F));
5282 output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
5283 output[3] = (char)NK_TO_HEX((col.g & 0x0F));
5284 output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
5285 output[5] = (char)NK_TO_HEX((col.b & 0x0F));
5286 output[6] = '\0';
5287 #undef NK_TO_HEX
5288}
5289
5290NK_API struct nk_color
5291nk_rgba_iv(const int *c)
5292{
5293 return nk_rgba(c[0], c[1], c[2], c[3]);
5294}
5295
5296NK_API struct nk_color
5297nk_rgba_bv(const nk_byte *c)
5298{
5299 return nk_rgba(c[0], c[1], c[2], c[3]);
5300}
5301
5302NK_API struct nk_color
5303nk_rgb(int r, int g, int b)
5304{
5305 struct nk_color ret;
5306 ret.r = (nk_byte)NK_CLAMP(0, r, 255);
5307 ret.g = (nk_byte)NK_CLAMP(0, g, 255);
5308 ret.b = (nk_byte)NK_CLAMP(0, b, 255);
5309 ret.a = (nk_byte)255;
5310 return ret;
5311}
5312
5313NK_API struct nk_color
5314nk_rgb_iv(const int *c)
5315{
5316 return nk_rgb(c[0], c[1], c[2]);
5317}
5318
5319NK_API struct nk_color
5320nk_rgb_bv(const nk_byte* c)
5321{
5322 return nk_rgb(c[0], c[1], c[2]);
5323}
5324
5325NK_API struct nk_color
5326nk_rgba_u32(nk_uint in)
5327{
5328 struct nk_color ret;
5329 ret.r = (in & 0xFF);
5330 ret.g = ((in >> 8) & 0xFF);
5331 ret.b = ((in >> 16) & 0xFF);
5332 ret.a = (nk_byte)((in >> 24) & 0xFF);
5333 return ret;
5334}
5335
5336NK_API struct nk_color
5337nk_rgba_f(float r, float g, float b, float a)
5338{
5339 struct nk_color ret;
5340 ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
5341 ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
5342 ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
5343 ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f);
5344 return ret;
5345}
5346
5347NK_API struct nk_color
5348nk_rgba_fv(const float *c)
5349{
5350 return nk_rgba_f(c[0], c[1], c[2], c[3]);
5351}
5352
5353NK_API struct nk_color
5354nk_rgb_f(float r, float g, float b)
5355{
5356 struct nk_color ret;
5357 ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
5358 ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
5359 ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
5360 ret.a = 255;
5361 return ret;
5362}
5363
5364NK_API struct nk_color
5365nk_rgb_fv(const float *c)
5366{
5367 return nk_rgb_f(c[0], c[1], c[2]);
5368}
5369
5370NK_API struct nk_color
5371nk_hsv(int h, int s, int v)
5372{
5373 return nk_hsva(h, s, v, 255);
5374}
5375
5376NK_API struct nk_color
5377nk_hsv_iv(const int *c)
5378{
5379 return nk_hsv(c[0], c[1], c[2]);
5380}
5381
5382NK_API struct nk_color
5383nk_hsv_bv(const nk_byte *c)
5384{
5385 return nk_hsv(c[0], c[1], c[2]);
5386}
5387
5388NK_API struct nk_color
5389nk_hsv_f(float h, float s, float v)
5390{
5391 return nk_hsva_f(h, s, v, 1.0f);
5392}
5393
5394NK_API struct nk_color
5395nk_hsv_fv(const float *c)
5396{
5397 return nk_hsv_f(c[0], c[1], c[2]);
5398}
5399
5400NK_API struct nk_color
5401nk_hsva(int h, int s, int v, int a)
5402{
5403 float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f;
5404 float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f;
5405 float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f;
5406 float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f;
5407 return nk_hsva_f(hf, sf, vf, af);
5408}
5409
5410NK_API struct nk_color
5411nk_hsva_iv(const int *c)
5412{
5413 return nk_hsva(c[0], c[1], c[2], c[3]);
5414}
5415
5416NK_API struct nk_color
5417nk_hsva_bv(const nk_byte *c)
5418{
5419 return nk_hsva(c[0], c[1], c[2], c[3]);
5420}
5421
5422NK_API struct nk_color
5423nk_hsva_f(float h, float s, float v, float a)
5424{
5425 struct nk_colorf out = {0,0,0,0};
5426 float p, q, t, f;
5427 int i;
5428
5429 if (s <= 0.0f) {
5430 out.r = v; out.g = v; out.b = v;
5431 return nk_rgb_f(out.r, out.g, out.b);
5432 }
5433
5434 h = h / (60.0f/360.0f);
5435 i = (int)h;
5436 f = h - (float)i;
5437 p = v * (1.0f - s);
5438 q = v * (1.0f - (s * f));
5439 t = v * (1.0f - s * (1.0f - f));
5440
5441 switch (i) {
5442 case 0: default: out.r = v; out.g = t; out.b = p; break;
5443 case 1: out.r = q; out.g = v; out.b = p; break;
5444 case 2: out.r = p; out.g = v; out.b = t; break;
5445 case 3: out.r = p; out.g = q; out.b = v; break;
5446 case 4: out.r = t; out.g = p; out.b = v; break;
5447 case 5: out.r = v; out.g = p; out.b = q; break;
5448 }
5449 return nk_rgba_f(out.r, out.g, out.b, a);
5450}
5451
5452NK_API struct nk_color
5453nk_hsva_fv(const float *c)
5454{
5455 return nk_hsva_f(c[0], c[1], c[2], c[3]);
5456}
5457
5458NK_API nk_uint
5459nk_color_u32(struct nk_color in)
5460{
5461 nk_uint out = (nk_uint)in.r;
5462 out |= ((nk_uint)in.g << 8);
5463 out |= ((nk_uint)in.b << 16);
5464 out |= ((nk_uint)in.a << 24);
5465 return out;
5466}
5467
5468NK_API void
5469nk_color_f(float *r, float *g, float *b, float *a, struct nk_color in)
5470{
5471 NK_STORAGE const float s = 1.0f/255.0f;
5472 *r = (float)in.r * s;
5473 *g = (float)in.g * s;
5474 *b = (float)in.b * s;
5475 *a = (float)in.a * s;
5476}
5477
5478NK_API void
5479nk_color_fv(float *c, struct nk_color in)
5480{
5481 nk_color_f(&c[0], &c[1], &c[2], &c[3], in);
5482}
5483
5484NK_API void
5485nk_color_d(double *r, double *g, double *b, double *a, struct nk_color in)
5486{
5487 NK_STORAGE const double s = 1.0/255.0;
5488 *r = (double)in.r * s;
5489 *g = (double)in.g * s;
5490 *b = (double)in.b * s;
5491 *a = (double)in.a * s;
5492}
5493
5494NK_API void
5495nk_color_dv(double *c, struct nk_color in)
5496{
5497 nk_color_d(&c[0], &c[1], &c[2], &c[3], in);
5498}
5499
5500NK_API void
5501nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in)
5502{
5503 float a;
5504 nk_color_hsva_f(out_h, out_s, out_v, &a, in);
5505}
5506
5507NK_API void
5508nk_color_hsv_fv(float *out, struct nk_color in)
5509{
5510 float a;
5511 nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in);
5512}
5513
5514NK_API void
5515nk_color_hsva_f(float *out_h, float *out_s,
5516 float *out_v, float *out_a, struct nk_color in)
5517{
5518 float chroma;
5519 float K = 0.0f;
5520 float r,g,b,a;
5521
5522 nk_color_f(&r,&g,&b,&a, in);
5523 if (g < b) {
5524 const float t = g; g = b; b = t;
5525 K = -1.f;
5526 }
5527 if (r < g) {
5528 const float t = r; r = g; g = t;
5529 K = -2.f/6.0f - K;
5530 }
5531 chroma = r - ((g < b) ? g: b);
5532 *out_h = NK_ABS(K + (g - b)/(6.0f * chroma + 1e-20f));
5533 *out_s = chroma / (r + 1e-20f);
5534 *out_v = r;
5535 *out_a = (float)in.a / 255.0f;
5536}
5537
5538NK_API void
5539nk_color_hsva_fv(float *out, struct nk_color in)
5540{
5541 nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in);
5542}
5543
5544NK_API void
5545nk_color_hsva_i(int *out_h, int *out_s, int *out_v,
5546 int *out_a, struct nk_color in)
5547{
5548 float h,s,v,a;
5549 nk_color_hsva_f(&h, &s, &v, &a, in);
5550 *out_h = (nk_byte)(h * 255.0f);
5551 *out_s = (nk_byte)(s * 255.0f);
5552 *out_v = (nk_byte)(v * 255.0f);
5553 *out_a = (nk_byte)(a * 255.0f);
5554}
5555
5556NK_API void
5557nk_color_hsva_iv(int *out, struct nk_color in)
5558{
5559 nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in);
5560}
5561
5562NK_API void
5563nk_color_hsva_bv(nk_byte *out, struct nk_color in)
5564{
5565 int tmp[4];
5566 nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
5567 out[0] = (nk_byte)tmp[0];
5568 out[1] = (nk_byte)tmp[1];
5569 out[2] = (nk_byte)tmp[2];
5570 out[3] = (nk_byte)tmp[3];
5571}
5572
5573NK_API void
5574nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in)
5575{
5576 int tmp[4];
5577 nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
5578 *h = (nk_byte)tmp[0];
5579 *s = (nk_byte)tmp[1];
5580 *v = (nk_byte)tmp[2];
5581 *a = (nk_byte)tmp[3];
5582}
5583
5584NK_API void
5585nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in)
5586{
5587 int a;
5588 nk_color_hsva_i(out_h, out_s, out_v, &a, in);
5589}
5590
5591NK_API void
5592nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in)
5593{
5594 int tmp[4];
5595 nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
5596 *out_h = (nk_byte)tmp[0];
5597 *out_s = (nk_byte)tmp[1];
5598 *out_v = (nk_byte)tmp[2];
5599}
5600
5601NK_API void
5602nk_color_hsv_iv(int *out, struct nk_color in)
5603{
5604 nk_color_hsv_i(&out[0], &out[1], &out[2], in);
5605}
5606
5607NK_API void
5608nk_color_hsv_bv(nk_byte *out, struct nk_color in)
5609{
5610 int tmp[4];
5611 nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in);
5612 out[0] = (nk_byte)tmp[0];
5613 out[1] = (nk_byte)tmp[1];
5614 out[2] = (nk_byte)tmp[2];
5615}
5616/*
5617 * ==============================================================
5618 *
5619 * IMAGE
5620 *
5621 * ===============================================================
5622 */
5623NK_API nk_handle
5624nk_handle_ptr(void *ptr)
5625{
5626 nk_handle handle = {0};
5627 handle.ptr = ptr;
5628 return handle;
5629}
5630
5631NK_API nk_handle
5632nk_handle_id(int id)
5633{
5634 nk_handle handle;
5635 nk_zero_struct(handle);
5636 handle.id = id;
5637 return handle;
5638}
5639
5640NK_API struct nk_image
5641nk_subimage_ptr(void *ptr, unsigned short w, unsigned short h, struct nk_rect r)
5642{
5643 struct nk_image s;
5644 nk_zero(&s, sizeof(s));
5645 s.handle.ptr = ptr;
5646 s.w = w; s.h = h;
5647 s.region[0] = (unsigned short)r.x;
5648 s.region[1] = (unsigned short)r.y;
5649 s.region[2] = (unsigned short)r.w;
5650 s.region[3] = (unsigned short)r.h;
5651 return s;
5652}
5653
5654NK_API struct nk_image
5655nk_subimage_id(int id, unsigned short w, unsigned short h, struct nk_rect r)
5656{
5657 struct nk_image s;
5658 nk_zero(&s, sizeof(s));
5659 s.handle.id = id;
5660 s.w = w; s.h = h;
5661 s.region[0] = (unsigned short)r.x;
5662 s.region[1] = (unsigned short)r.y;
5663 s.region[2] = (unsigned short)r.w;
5664 s.region[3] = (unsigned short)r.h;
5665 return s;
5666}
5667
5668NK_API struct nk_image
5669nk_subimage_handle(nk_handle handle, unsigned short w, unsigned short h,
5670 struct nk_rect r)
5671{
5672 struct nk_image s;
5673 nk_zero(&s, sizeof(s));
5674 s.handle = handle;
5675 s.w = w; s.h = h;
5676 s.region[0] = (unsigned short)r.x;
5677 s.region[1] = (unsigned short)r.y;
5678 s.region[2] = (unsigned short)r.w;
5679 s.region[3] = (unsigned short)r.h;
5680 return s;
5681}
5682
5683NK_API struct nk_image
5684nk_image_handle(nk_handle handle)
5685{
5686 struct nk_image s;
5687 nk_zero(&s, sizeof(s));
5688 s.handle = handle;
5689 s.w = 0; s.h = 0;
5690 s.region[0] = 0;
5691 s.region[1] = 0;
5692 s.region[2] = 0;
5693 s.region[3] = 0;
5694 return s;
5695}
5696
5697NK_API struct nk_image
5698nk_image_ptr(void *ptr)
5699{
5700 struct nk_image s;
5701 nk_zero(&s, sizeof(s));
5702 NK_ASSERT(ptr);
5703 s.handle.ptr = ptr;
5704 s.w = 0; s.h = 0;
5705 s.region[0] = 0;
5706 s.region[1] = 0;
5707 s.region[2] = 0;
5708 s.region[3] = 0;
5709 return s;
5710}
5711
5712NK_API struct nk_image
5713nk_image_id(int id)
5714{
5715 struct nk_image s;
5716 nk_zero(&s, sizeof(s));
5717 s.handle.id = id;
5718 s.w = 0; s.h = 0;
5719 s.region[0] = 0;
5720 s.region[1] = 0;
5721 s.region[2] = 0;
5722 s.region[3] = 0;
5723 return s;
5724}
5725
5726NK_API int
5727nk_image_is_subimage(const struct nk_image* img)
5728{
5729 NK_ASSERT(img);
5730 return !(img->w == 0 && img->h == 0);
5731}
5732
5733NK_INTERN void
5734nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0,
5735 float x1, float y1)
5736{
5737 NK_ASSERT(a);
5738 NK_ASSERT(clip);
5739 clip->x = NK_MAX(a->x, x0);
5740 clip->y = NK_MAX(a->y, y0);
5741 clip->w = NK_MIN(a->x + a->w, x1) - clip->x;
5742 clip->h = NK_MIN(a->y + a->h, y1) - clip->y;
5743 clip->w = NK_MAX(0, clip->w);
5744 clip->h = NK_MAX(0, clip->h);
5745}
5746
5747NK_API void
5748nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r,
5749 float pad_x, float pad_y, enum nk_heading direction)
5750{
5751 float w_half, h_half;
5752 NK_ASSERT(result);
5753
5754 r.w = NK_MAX(2 * pad_x, r.w);
5755 r.h = NK_MAX(2 * pad_y, r.h);
5756 r.w = r.w - 2 * pad_x;
5757 r.h = r.h - 2 * pad_y;
5758
5759 r.x = r.x + pad_x;
5760 r.y = r.y + pad_y;
5761
5762 w_half = r.w / 2.0f;
5763 h_half = r.h / 2.0f;
5764
5765 if (direction == NK_UP) {
5766 result[0] = nk_vec2(r.x + w_half, r.y);
5767 result[1] = nk_vec2(r.x + r.w, r.y + r.h);
5768 result[2] = nk_vec2(r.x, r.y + r.h);
5769 } else if (direction == NK_RIGHT) {
5770 result[0] = nk_vec2(r.x, r.y);
5771 result[1] = nk_vec2(r.x + r.w, r.y + h_half);
5772 result[2] = nk_vec2(r.x, r.y + r.h);
5773 } else if (direction == NK_DOWN) {
5774 result[0] = nk_vec2(r.x, r.y);
5775 result[1] = nk_vec2(r.x + r.w, r.y);
5776 result[2] = nk_vec2(r.x + w_half, r.y + r.h);
5777 } else {
5778 result[0] = nk_vec2(r.x, r.y + h_half);
5779 result[1] = nk_vec2(r.x + r.w, r.y);
5780 result[2] = nk_vec2(r.x + r.w, r.y + r.h);
5781 }
5782}
5783
5784NK_INTERN int
5785nk_text_clamp(const struct nk_user_font *font, const char *text,
5786 int text_len, float space, int *glyphs, float *text_width,
5787 nk_rune *sep_list, int sep_count)
5788{
5789 int i = 0;
5790 int glyph_len = 0;
5791 float last_width = 0;
5792 nk_rune unicode = 0;
5793 float width = 0;
5794 int len = 0;
5795 int g = 0;
5796 float s;
5797
5798 int sep_len = 0;
5799 int sep_g = 0;
5800 float sep_width = 0;
5801 sep_count = NK_MAX(sep_count,0);
5802
5803 glyph_len = nk_utf_decode(text, &unicode, text_len);
5804 while (glyph_len && (width < space) && (len < text_len)) {
5805 len += glyph_len;
5806 s = font->width(font->userdata, font->height, text, len);
5807 for (i = 0; i < sep_count; ++i) {
5808 if (unicode != sep_list[i]) continue;
5809 sep_width = last_width = width;
5810 sep_g = g+1;
5811 sep_len = len;
5812 break;
5813 }
5814 if (i == NK_MAX(sep_count,0)){
5815 last_width = sep_width = width;
5816 sep_g = g+1;
5817 }
5818 width = s;
5819 glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len);
5820 g++;
5821 }
5822 if (len >= text_len) {
5823 *glyphs = g;
5824 *text_width = last_width;
5825 return len;
5826 } else {
5827 *glyphs = sep_g;
5828 *text_width = sep_width;
5829 return (!sep_len) ? len: sep_len;
5830 }
5831}
5832
5833enum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE};
5834NK_INTERN struct nk_vec2
5835nk_text_calculate_text_bounds(const struct nk_user_font *font,
5836 const char *begin, int byte_len, float row_height, const char **remaining,
5837 struct nk_vec2 *out_offset, int *glyphs, int op)
5838{
5839 float line_height = row_height;
5840 struct nk_vec2 text_size = nk_vec2(0,0);
5841 float line_width = 0.0f;
5842
5843 float glyph_width;
5844 int glyph_len = 0;
5845 nk_rune unicode = 0;
5846 int text_len = 0;
5847 if (!begin || byte_len <= 0 || !font)
5848 return nk_vec2(0,row_height);
5849
5850 glyph_len = nk_utf_decode(begin, &unicode, byte_len);
5851 if (!glyph_len) return text_size;
5852 glyph_width = font->width(font->userdata, font->height, begin, glyph_len);
5853
5854 *glyphs = 0;
5855 while ((text_len < byte_len) && glyph_len) {
5856 if (unicode == '\n') {
5857 text_size.x = NK_MAX(text_size.x, line_width);
5858 text_size.y += line_height;
5859 line_width = 0;
5860 *glyphs+=1;
5861 if (op == NK_STOP_ON_NEW_LINE)
5862 break;
5863
5864 text_len++;
5865 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
5866 continue;
5867 }
5868
5869 if (unicode == '\r') {
5870 text_len++;
5871 *glyphs+=1;
5872 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
5873 continue;
5874 }
5875
5876 *glyphs = *glyphs + 1;
5877 text_len += glyph_len;
5878 line_width += (float)glyph_width;
5879 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
5880 glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len);
5881 continue;
5882 }
5883
5884 if (text_size.x < line_width)
5885 text_size.x = line_width;
5886 if (out_offset)
5887 *out_offset = nk_vec2(line_width, text_size.y + line_height);
5888 if (line_width > 0 || text_size.y == 0.0f)
5889 text_size.y += line_height;
5890 if (remaining)
5891 *remaining = begin+text_len;
5892 return text_size;
5893}
5894
5895/* ==============================================================
5896 *
5897 * UTF-8
5898 *
5899 * ===============================================================*/
5900NK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
5901NK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
5902NK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000};
5903NK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
5904
5905NK_INTERN int
5906nk_utf_validate(nk_rune *u, int i)
5907{
5908 NK_ASSERT(u);
5909 if (!u) return 0;
5910 if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) ||
5911 NK_BETWEEN(*u, 0xD800, 0xDFFF))
5912 *u = NK_UTF_INVALID;
5913 for (i = 1; *u > nk_utfmax[i]; ++i);
5914 return i;
5915}
5916
5917NK_INTERN nk_rune
5918nk_utf_decode_byte(char c, int *i)
5919{
5920 NK_ASSERT(i);
5921 if (!i) return 0;
5922 for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) {
5923 if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i])
5924 return (nk_byte)(c & ~nk_utfmask[*i]);
5925 }
5926 return 0;
5927}
5928
5929NK_API int
5930nk_utf_decode(const char *c, nk_rune *u, int clen)
5931{
5932 int i, j, len, type=0;
5933 nk_rune udecoded;
5934
5935 NK_ASSERT(c);
5936 NK_ASSERT(u);
5937
5938 if (!c || !u) return 0;
5939 if (!clen) return 0;
5940 *u = NK_UTF_INVALID;
5941
5942 udecoded = nk_utf_decode_byte(c[0], &len);
5943 if (!NK_BETWEEN(len, 1, NK_UTF_SIZE))
5944 return 1;
5945
5946 for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
5947 udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type);
5948 if (type != 0)
5949 return j;
5950 }
5951 if (j < len)
5952 return 0;
5953 *u = udecoded;
5954 nk_utf_validate(u, len);
5955 return len;
5956}
5957
5958NK_INTERN char
5959nk_utf_encode_byte(nk_rune u, int i)
5960{
5961 return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i]));
5962}
5963
5964NK_API int
5965nk_utf_encode(nk_rune u, char *c, int clen)
5966{
5967 int len, i;
5968 len = nk_utf_validate(&u, 0);
5969 if (clen < len || !len || len > NK_UTF_SIZE)
5970 return 0;
5971
5972 for (i = len - 1; i != 0; --i) {
5973 c[i] = nk_utf_encode_byte(u, 0);
5974 u >>= 6;
5975 }
5976 c[0] = nk_utf_encode_byte(u, len);
5977 return len;
5978}
5979
5980NK_API int
5981nk_utf_len(const char *str, int len)
5982{
5983 const char *text;
5984 int glyphs = 0;
5985 int text_len;
5986 int glyph_len;
5987 int src_len = 0;
5988 nk_rune unicode;
5989
5990 NK_ASSERT(str);
5991 if (!str || !len) return 0;
5992
5993 text = str;
5994 text_len = len;
5995 glyph_len = nk_utf_decode(text, &unicode, text_len);
5996 while (glyph_len && src_len < len) {
5997 glyphs++;
5998 src_len = src_len + glyph_len;
5999 glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len);
6000 }
6001 return glyphs;
6002}
6003
6004NK_API const char*
6005nk_utf_at(const char *buffer, int length, int index,
6006 nk_rune *unicode, int *len)
6007{
6008 int i = 0;
6009 int src_len = 0;
6010 int glyph_len = 0;
6011 const char *text;
6012 int text_len;
6013
6014 NK_ASSERT(buffer);
6015 NK_ASSERT(unicode);
6016 NK_ASSERT(len);
6017
6018 if (!buffer || !unicode || !len) return 0;
6019 if (index < 0) {
6020 *unicode = NK_UTF_INVALID;
6021 *len = 0;
6022 return 0;
6023 }
6024
6025 text = buffer;
6026 text_len = length;
6027 glyph_len = nk_utf_decode(text, unicode, text_len);
6028 while (glyph_len) {
6029 if (i == index) {
6030 *len = glyph_len;
6031 break;
6032 }
6033
6034 i++;
6035 src_len = src_len + glyph_len;
6036 glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
6037 }
6038 if (i != index) return 0;
6039 return buffer + src_len;
6040}
6041
6042/* ==============================================================
6043 *
6044 * BUFFER
6045 *
6046 * ===============================================================*/
6047#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
6048NK_INTERN void* nk_malloc(nk_handle unused, void *old,nk_size size)
6049{NK_UNUSED(unused); NK_UNUSED(old); return malloc(size);}
6050NK_INTERN void nk_mfree(nk_handle unused, void *ptr)
6051{NK_UNUSED(unused); free(ptr);}
6052
6053NK_API void
6054nk_buffer_init_default(struct nk_buffer *buffer)
6055{
6056 struct nk_allocator alloc;
6057 alloc.userdata.ptr = 0;
6058 alloc.alloc = nk_malloc;
6059 alloc.free = nk_mfree;
6060 nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE);
6061}
6062#endif
6063
6064NK_API void
6065nk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a,
6066 nk_size initial_size)
6067{
6068 NK_ASSERT(b);
6069 NK_ASSERT(a);
6070 NK_ASSERT(initial_size);
6071 if (!b || !a || !initial_size) return;
6072
6073 nk_zero(b, sizeof(*b));
6074 b->type = NK_BUFFER_DYNAMIC;
6075 b->memory.ptr = a->alloc(a->userdata,0, initial_size);
6076 b->memory.size = initial_size;
6077 b->size = initial_size;
6078 b->grow_factor = 2.0f;
6079 b->pool = *a;
6080}
6081
6082NK_API void
6083nk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size)
6084{
6085 NK_ASSERT(b);
6086 NK_ASSERT(m);
6087 NK_ASSERT(size);
6088 if (!b || !m || !size) return;
6089
6090 nk_zero(b, sizeof(*b));
6091 b->type = NK_BUFFER_FIXED;
6092 b->memory.ptr = m;
6093 b->memory.size = size;
6094 b->size = size;
6095}
6096
6097NK_INTERN void*
6098nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment,
6099 enum nk_buffer_allocation_type type)
6100{
6101 void *memory = 0;
6102 switch (type) {
6103 default:
6104 case NK_BUFFER_MAX:
6105 case NK_BUFFER_FRONT:
6106 if (align) {
6107 memory = NK_ALIGN_PTR(unaligned, align);
6108 *alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);
6109 } else {
6110 memory = unaligned;
6111 *alignment = 0;
6112 }
6113 break;
6114 case NK_BUFFER_BACK:
6115 if (align) {
6116 memory = NK_ALIGN_PTR_BACK(unaligned, align);
6117 *alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory);
6118 } else {
6119 memory = unaligned;
6120 *alignment = 0;
6121 }
6122 break;
6123 }
6124 return memory;
6125}
6126
6127NK_INTERN void*
6128nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size)
6129{
6130 void *temp;
6131 nk_size buffer_size;
6132
6133 NK_ASSERT(b);
6134 NK_ASSERT(size);
6135 if (!b || !size || !b->pool.alloc || !b->pool.free)
6136 return 0;
6137
6138 buffer_size = b->memory.size;
6139 temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity);
6140 NK_ASSERT(temp);
6141 if (!temp) return 0;
6142
6143 *size = capacity;
6144 if (temp != b->memory.ptr) {
6145 NK_MEMCPY(temp, b->memory.ptr, buffer_size);
6146 b->pool.free(b->pool.userdata, b->memory.ptr);
6147 }
6148
6149 if (b->size == buffer_size) {
6150 /* no back buffer so just set correct size */
6151 b->size = capacity;
6152 return temp;
6153 } else {
6154 /* copy back buffer to the end of the new buffer */
6155 void *dst, *src;
6156 nk_size back_size;
6157 back_size = buffer_size - b->size;
6158 dst = nk_ptr_add(void, temp, capacity - back_size);
6159 src = nk_ptr_add(void, temp, b->size);
6160 NK_MEMCPY(dst, src, back_size);
6161 b->size = capacity - back_size;
6162 }
6163 return temp;
6164}
6165
6166NK_INTERN void*
6167nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type,
6168 nk_size size, nk_size align)
6169{
6170 int full;
6171 nk_size alignment;
6172 void *unaligned;
6173 void *memory;
6174
6175 NK_ASSERT(b);
6176 NK_ASSERT(size);
6177 if (!b || !size) return 0;
6178 b->needed += size;
6179
6180 /* calculate total size with needed alignment + size */
6181 if (type == NK_BUFFER_FRONT)
6182 unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);
6183 else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);
6184 memory = nk_buffer_align(unaligned, align, &alignment, type);
6185
6186 /* check if buffer has enough memory*/
6187 if (type == NK_BUFFER_FRONT)
6188 full = ((b->allocated + size + alignment) > b->size);
6189 else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated);
6190
6191 if (full) {
6192 nk_size capacity;
6193 if (b->type != NK_BUFFER_DYNAMIC)
6194 return 0;
6195 NK_ASSERT(b->pool.alloc && b->pool.free);
6196 if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free)
6197 return 0;
6198
6199 /* buffer is full so allocate bigger buffer if dynamic */
6200 capacity = (nk_size)((float)b->memory.size * b->grow_factor);
6201 capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size)));
6202 b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size);
6203 if (!b->memory.ptr) return 0;
6204
6205 /* align newly allocated pointer */
6206 if (type == NK_BUFFER_FRONT)
6207 unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);
6208 else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);
6209 memory = nk_buffer_align(unaligned, align, &alignment, type);
6210 }
6211
6212 if (type == NK_BUFFER_FRONT)
6213 b->allocated += size + alignment;
6214 else b->size -= (size + alignment);
6215 b->needed += alignment;
6216 b->calls++;
6217 return memory;
6218}
6219
6220NK_API void
6221nk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type,
6222 const void *memory, nk_size size, nk_size align)
6223{
6224 void *mem = nk_buffer_alloc(b, type, size, align);
6225 if (!mem) return;
6226 NK_MEMCPY(mem, memory, size);
6227}
6228
6229NK_API void
6230nk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)
6231{
6232 NK_ASSERT(buffer);
6233 if (!buffer) return;
6234 buffer->marker[type].active = nk_true;
6235 if (type == NK_BUFFER_BACK)
6236 buffer->marker[type].offset = buffer->size;
6237 else buffer->marker[type].offset = buffer->allocated;
6238}
6239
6240NK_API void
6241nk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)
6242{
6243 NK_ASSERT(buffer);
6244 if (!buffer) return;
6245 if (type == NK_BUFFER_BACK) {
6246 /* reset back buffer either back to marker or empty */
6247 buffer->needed -= (buffer->memory.size - buffer->marker[type].offset);
6248 if (buffer->marker[type].active)
6249 buffer->size = buffer->marker[type].offset;
6250 else buffer->size = buffer->memory.size;
6251 buffer->marker[type].active = nk_false;
6252 } else {
6253 /* reset front buffer either back to back marker or empty */
6254 buffer->needed -= (buffer->allocated - buffer->marker[type].offset);
6255 if (buffer->marker[type].active)
6256 buffer->allocated = buffer->marker[type].offset;
6257 else buffer->allocated = 0;
6258 buffer->marker[type].active = nk_false;
6259 }
6260}
6261
6262NK_API void
6263nk_buffer_clear(struct nk_buffer *b)
6264{
6265 NK_ASSERT(b);
6266 if (!b) return;
6267 b->allocated = 0;
6268 b->size = b->memory.size;
6269 b->calls = 0;
6270 b->needed = 0;
6271}
6272
6273NK_API void
6274nk_buffer_free(struct nk_buffer *b)
6275{
6276 NK_ASSERT(b);
6277 if (!b || !b->memory.ptr) return;
6278 if (b->type == NK_BUFFER_FIXED) return;
6279 if (!b->pool.free) return;
6280 NK_ASSERT(b->pool.free);
6281 b->pool.free(b->pool.userdata, b->memory.ptr);
6282}
6283
6284NK_API void
6285nk_buffer_info(struct nk_memory_status *s, struct nk_buffer *b)
6286{
6287 NK_ASSERT(b);
6288 NK_ASSERT(s);
6289 if (!s || !b) return;
6290 s->allocated = b->allocated;
6291 s->size = b->memory.size;
6292 s->needed = b->needed;
6293 s->memory = b->memory.ptr;
6294 s->calls = b->calls;
6295}
6296
6297NK_API void*
6298nk_buffer_memory(struct nk_buffer *buffer)
6299{
6300 NK_ASSERT(buffer);
6301 if (!buffer) return 0;
6302 return buffer->memory.ptr;
6303}
6304
6305NK_API const void*
6306nk_buffer_memory_const(const struct nk_buffer *buffer)
6307{
6308 NK_ASSERT(buffer);
6309 if (!buffer) return 0;
6310 return buffer->memory.ptr;
6311}
6312
6313NK_API nk_size
6314nk_buffer_total(struct nk_buffer *buffer)
6315{
6316 NK_ASSERT(buffer);
6317 if (!buffer) return 0;
6318 return buffer->memory.size;
6319}
6320
6321/*
6322 * ==============================================================
6323 *
6324 * STRING
6325 *
6326 * ===============================================================
6327 */
6328#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
6329NK_API void
6330nk_str_init_default(struct nk_str *str)
6331{
6332 struct nk_allocator alloc;
6333 alloc.userdata.ptr = 0;
6334 alloc.alloc = nk_malloc;
6335 alloc.free = nk_mfree;
6336 nk_buffer_init(&str->buffer, &alloc, 32);
6337 str->len = 0;
6338}
6339#endif
6340
6341NK_API void
6342nk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size)
6343{
6344 nk_buffer_init(&str->buffer, alloc, size);
6345 str->len = 0;
6346}
6347
6348NK_API void
6349nk_str_init_fixed(struct nk_str *str, void *memory, nk_size size)
6350{
6351 nk_buffer_init_fixed(&str->buffer, memory, size);
6352 str->len = 0;
6353}
6354
6355NK_API int
6356nk_str_append_text_char(struct nk_str *s, const char *str, int len)
6357{
6358 char *mem;
6359 NK_ASSERT(s);
6360 NK_ASSERT(str);
6361 if (!s || !str || !len) return 0;
6362 mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);
6363 if (!mem) return 0;
6364 NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));
6365 s->len += nk_utf_len(str, len);
6366 return len;
6367}
6368
6369NK_API int
6370nk_str_append_str_char(struct nk_str *s, const char *str)
6371{
6372 return nk_str_append_text_char(s, str, nk_strlen(str));
6373}
6374
6375NK_API int
6376nk_str_append_text_utf8(struct nk_str *str, const char *text, int len)
6377{
6378 int i = 0;
6379 int byte_len = 0;
6380 nk_rune unicode;
6381 if (!str || !text || !len) return 0;
6382 for (i = 0; i < len; ++i)
6383 byte_len += nk_utf_decode(text+byte_len, &unicode, 4);
6384 nk_str_append_text_char(str, text, byte_len);
6385 return len;
6386}
6387
6388NK_API int
6389nk_str_append_str_utf8(struct nk_str *str, const char *text)
6390{
6391 int runes = 0;
6392 int byte_len = 0;
6393 int num_runes = 0;
6394 int glyph_len = 0;
6395 nk_rune unicode;
6396 if (!str || !text) return 0;
6397
6398 glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);
6399 while (unicode != '\0' && glyph_len) {
6400 glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);
6401 byte_len += glyph_len;
6402 num_runes++;
6403 }
6404 nk_str_append_text_char(str, text, byte_len);
6405 return runes;
6406}
6407
6408NK_API int
6409nk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len)
6410{
6411 int i = 0;
6412 int byte_len = 0;
6413 nk_glyph glyph;
6414
6415 NK_ASSERT(str);
6416 if (!str || !text || !len) return 0;
6417 for (i = 0; i < len; ++i) {
6418 byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE);
6419 if (!byte_len) break;
6420 nk_str_append_text_char(str, glyph, byte_len);
6421 }
6422 return len;
6423}
6424
6425NK_API int
6426nk_str_append_str_runes(struct nk_str *str, const nk_rune *runes)
6427{
6428 int i = 0;
6429 nk_glyph glyph;
6430 int byte_len;
6431 NK_ASSERT(str);
6432 if (!str || !runes) return 0;
6433 while (runes[i] != '\0') {
6434 byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
6435 nk_str_append_text_char(str, glyph, byte_len);
6436 i++;
6437 }
6438 return i;
6439}
6440
6441NK_API int
6442nk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len)
6443{
6444 int i;
6445 void *mem;
6446 char *src;
6447 char *dst;
6448
6449 int copylen;
6450 NK_ASSERT(s);
6451 NK_ASSERT(str);
6452 NK_ASSERT(len >= 0);
6453 if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0;
6454 if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) &&
6455 (s->buffer.type == NK_BUFFER_FIXED)) return 0;
6456
6457 copylen = (int)s->buffer.allocated - pos;
6458 if (!copylen) {
6459 nk_str_append_text_char(s, str, len);
6460 return 1;
6461 }
6462 mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);
6463 if (!mem) return 0;
6464
6465 /* memmove */
6466 NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0);
6467 NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0);
6468 dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1));
6469 src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1));
6470 for (i = 0; i < copylen; ++i) *dst-- = *src--;
6471 mem = nk_ptr_add(void, s->buffer.memory.ptr, pos);
6472 NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));
6473 s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
6474 return 1;
6475}
6476
6477NK_API int
6478nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len)
6479{
6480 int glyph_len;
6481 nk_rune unicode;
6482 const char *begin;
6483 const char *buffer;
6484
6485 NK_ASSERT(str);
6486 NK_ASSERT(cstr);
6487 NK_ASSERT(len);
6488 if (!str || !cstr || !len) return 0;
6489 begin = nk_str_at_rune(str, pos, &unicode, &glyph_len);
6490 if (!str->len)
6491 return nk_str_append_text_char(str, cstr, len);
6492 buffer = nk_str_get_const(str);
6493 if (!begin) return 0;
6494 return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len);
6495}
6496
6497NK_API int
6498nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len)
6499{
6500 return nk_str_insert_text_utf8(str, pos, text, len);
6501}
6502
6503NK_API int
6504nk_str_insert_str_char(struct nk_str *str, int pos, const char *text)
6505{
6506 return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text));
6507}
6508
6509NK_API int
6510nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len)
6511{
6512 int i = 0;
6513 int byte_len = 0;
6514 nk_rune unicode;
6515
6516 NK_ASSERT(str);
6517 NK_ASSERT(text);
6518 if (!str || !text || !len) return 0;
6519 for (i = 0; i < len; ++i)
6520 byte_len += nk_utf_decode(text+byte_len, &unicode, 4);
6521 nk_str_insert_at_rune(str, pos, text, byte_len);
6522 return len;
6523}
6524
6525NK_API int
6526nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text)
6527{
6528 int runes = 0;
6529 int byte_len = 0;
6530 int num_runes = 0;
6531 int glyph_len = 0;
6532 nk_rune unicode;
6533 if (!str || !text) return 0;
6534
6535 glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);
6536 while (unicode != '\0' && glyph_len) {
6537 glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);
6538 byte_len += glyph_len;
6539 num_runes++;
6540 }
6541 nk_str_insert_at_rune(str, pos, text, byte_len);
6542 return runes;
6543}
6544
6545NK_API int
6546nk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len)
6547{
6548 int i = 0;
6549 int byte_len = 0;
6550 nk_glyph glyph;
6551
6552 NK_ASSERT(str);
6553 if (!str || !runes || !len) return 0;
6554 for (i = 0; i < len; ++i) {
6555 byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
6556 if (!byte_len) break;
6557 nk_str_insert_at_rune(str, pos+i, glyph, byte_len);
6558 }
6559 return len;
6560}
6561
6562NK_API int
6563nk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes)
6564{
6565 int i = 0;
6566 nk_glyph glyph;
6567 int byte_len;
6568 NK_ASSERT(str);
6569 if (!str || !runes) return 0;
6570 while (runes[i] != '\0') {
6571 byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
6572 nk_str_insert_at_rune(str, pos+i, glyph, byte_len);
6573 i++;
6574 }
6575 return i;
6576}
6577
6578NK_API void
6579nk_str_remove_chars(struct nk_str *s, int len)
6580{
6581 NK_ASSERT(s);
6582 NK_ASSERT(len >= 0);
6583 if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return;
6584 NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);
6585 s->buffer.allocated -= (nk_size)len;
6586 s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
6587}
6588
6589NK_API void
6590nk_str_remove_runes(struct nk_str *str, int len)
6591{
6592 int index;
6593 const char *begin;
6594 const char *end;
6595 nk_rune unicode;
6596
6597 NK_ASSERT(str);
6598 NK_ASSERT(len >= 0);
6599 if (!str || len < 0) return;
6600 if (len >= str->len) {
6601 str->len = 0;
6602 return;
6603 }
6604
6605 index = str->len - len;
6606 begin = nk_str_at_rune(str, index, &unicode, &len);
6607 end = (const char*)str->buffer.memory.ptr + str->buffer.allocated;
6608 nk_str_remove_chars(str, (int)(end-begin)+1);
6609}
6610
6611NK_API void
6612nk_str_delete_chars(struct nk_str *s, int pos, int len)
6613{
6614 NK_ASSERT(s);
6615 if (!s || !len || (nk_size)pos > s->buffer.allocated ||
6616 (nk_size)(pos + len) > s->buffer.allocated) return;
6617
6618 if ((nk_size)(pos + len) < s->buffer.allocated) {
6619 /* memmove */
6620 char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos);
6621 char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len);
6622 NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len));
6623 NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);
6624 s->buffer.allocated -= (nk_size)len;
6625 } else nk_str_remove_chars(s, len);
6626 s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
6627}
6628
6629NK_API void
6630nk_str_delete_runes(struct nk_str *s, int pos, int len)
6631{
6632 char *temp;
6633 nk_rune unicode;
6634 char *begin;
6635 char *end;
6636 int unused;
6637
6638 NK_ASSERT(s);
6639 NK_ASSERT(s->len >= pos + len);
6640 if (s->len < pos + len)
6641 len = NK_CLAMP(0, (s->len - pos), s->len);
6642 if (!len) return;
6643
6644 temp = (char *)s->buffer.memory.ptr;
6645 begin = nk_str_at_rune(s, pos, &unicode, &unused);
6646 if (!begin) return;
6647 s->buffer.memory.ptr = begin;
6648 end = nk_str_at_rune(s, len, &unicode, &unused);
6649 s->buffer.memory.ptr = temp;
6650 if (!end) return;
6651 nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin));
6652}
6653
6654NK_API char*
6655nk_str_at_char(struct nk_str *s, int pos)
6656{
6657 NK_ASSERT(s);
6658 if (!s || pos > (int)s->buffer.allocated) return 0;
6659 return nk_ptr_add(char, s->buffer.memory.ptr, pos);
6660}
6661
6662NK_API char*
6663nk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len)
6664{
6665 int i = 0;
6666 int src_len = 0;
6667 int glyph_len = 0;
6668 char *text;
6669 int text_len;
6670
6671 NK_ASSERT(str);
6672 NK_ASSERT(unicode);
6673 NK_ASSERT(len);
6674
6675 if (!str || !unicode || !len) return 0;
6676 if (pos < 0) {
6677 *unicode = 0;
6678 *len = 0;
6679 return 0;
6680 }
6681
6682 text = (char*)str->buffer.memory.ptr;
6683 text_len = (int)str->buffer.allocated;
6684 glyph_len = nk_utf_decode(text, unicode, text_len);
6685 while (glyph_len) {
6686 if (i == pos) {
6687 *len = glyph_len;
6688 break;
6689 }
6690
6691 i++;
6692 src_len = src_len + glyph_len;
6693 glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
6694 }
6695 if (i != pos) return 0;
6696 return text + src_len;
6697}
6698
6699NK_API const char*
6700nk_str_at_char_const(const struct nk_str *s, int pos)
6701{
6702 NK_ASSERT(s);
6703 if (!s || pos > (int)s->buffer.allocated) return 0;
6704 return nk_ptr_add(char, s->buffer.memory.ptr, pos);
6705}
6706
6707NK_API const char*
6708nk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len)
6709{
6710 int i = 0;
6711 int src_len = 0;
6712 int glyph_len = 0;
6713 char *text;
6714 int text_len;
6715
6716 NK_ASSERT(str);
6717 NK_ASSERT(unicode);
6718 NK_ASSERT(len);
6719
6720 if (!str || !unicode || !len) return 0;
6721 if (pos < 0) {
6722 *unicode = 0;
6723 *len = 0;
6724 return 0;
6725 }
6726
6727 text = (char*)str->buffer.memory.ptr;
6728 text_len = (int)str->buffer.allocated;
6729 glyph_len = nk_utf_decode(text, unicode, text_len);
6730 while (glyph_len) {
6731 if (i == pos) {
6732 *len = glyph_len;
6733 break;
6734 }
6735
6736 i++;
6737 src_len = src_len + glyph_len;
6738 glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
6739 }
6740 if (i != pos) return 0;
6741 return text + src_len;
6742}
6743
6744NK_API nk_rune
6745nk_str_rune_at(const struct nk_str *str, int pos)
6746{
6747 int len;
6748 nk_rune unicode = 0;
6749 nk_str_at_const(str, pos, &unicode, &len);
6750 return unicode;
6751}
6752
6753NK_API char*
6754nk_str_get(struct nk_str *s)
6755{
6756 NK_ASSERT(s);
6757 if (!s || !s->len || !s->buffer.allocated) return 0;
6758 return (char*)s->buffer.memory.ptr;
6759}
6760
6761NK_API const char*
6762nk_str_get_const(const struct nk_str *s)
6763{
6764 NK_ASSERT(s);
6765 if (!s || !s->len || !s->buffer.allocated) return 0;
6766 return (const char*)s->buffer.memory.ptr;
6767}
6768
6769NK_API int
6770nk_str_len(struct nk_str *s)
6771{
6772 NK_ASSERT(s);
6773 if (!s || !s->len || !s->buffer.allocated) return 0;
6774 return s->len;
6775}
6776
6777NK_API int
6778nk_str_len_char(struct nk_str *s)
6779{
6780 NK_ASSERT(s);
6781 if (!s || !s->len || !s->buffer.allocated) return 0;
6782 return (int)s->buffer.allocated;
6783}
6784
6785NK_API void
6786nk_str_clear(struct nk_str *str)
6787{
6788 NK_ASSERT(str);
6789 nk_buffer_clear(&str->buffer);
6790 str->len = 0;
6791}
6792
6793NK_API void
6794nk_str_free(struct nk_str *str)
6795{
6796 NK_ASSERT(str);
6797 nk_buffer_free(&str->buffer);
6798 str->len = 0;
6799}
6800
6801/*
6802 * ==============================================================
6803 *
6804 * Command buffer
6805 *
6806 * ===============================================================
6807*/
6808NK_INTERN void
6809nk_command_buffer_init(struct nk_command_buffer *cmdbuf,
6810 struct nk_buffer *buffer, enum nk_command_clipping clip)
6811{
6812 NK_ASSERT(cmdbuf);
6813 NK_ASSERT(buffer);
6814 if (!cmdbuf || !buffer) return;
6815 cmdbuf->base = buffer;
6816 cmdbuf->use_clipping = clip;
6817 cmdbuf->begin = buffer->allocated;
6818 cmdbuf->end = buffer->allocated;
6819 cmdbuf->last = buffer->allocated;
6820}
6821
6822NK_INTERN void
6823nk_command_buffer_reset(struct nk_command_buffer *buffer)
6824{
6825 NK_ASSERT(buffer);
6826 if (!buffer) return;
6827 buffer->begin = 0;
6828 buffer->end = 0;
6829 buffer->last = 0;
6830 buffer->clip = nk_null_rect;
6831#ifdef NK_INCLUDE_COMMAND_USERDATA
6832 buffer->userdata.ptr = 0;
6833#endif
6834}
6835
6836NK_INTERN void*
6837nk_command_buffer_push(struct nk_command_buffer* b,
6838 enum nk_command_type t, nk_size size)
6839{
6840 NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command);
6841 struct nk_command *cmd;
6842 nk_size alignment;
6843 void *unaligned;
6844 void *memory;
6845
6846 NK_ASSERT(b);
6847 NK_ASSERT(b->base);
6848 if (!b) return 0;
6849 cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align);
6850 if (!cmd) return 0;
6851
6852 /* make sure the offset to the next command is aligned */
6853 b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr);
6854 unaligned = (nk_byte*)cmd + size;
6855 memory = NK_ALIGN_PTR(unaligned, align);
6856 alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);
6857#ifdef NK_ZERO_COMMAND_MEMORY
6858 NK_MEMSET(cmd, 0, size + alignment);
6859#endif
6860
6861 cmd->type = t;
6862 cmd->next = b->base->allocated + alignment;
6863#ifdef NK_INCLUDE_COMMAND_USERDATA
6864 cmd->userdata = b->userdata;
6865#endif
6866 b->end = cmd->next;
6867 return cmd;
6868}
6869
6870NK_API void
6871nk_push_scissor(struct nk_command_buffer *b, struct nk_rect r)
6872{
6873 struct nk_command_scissor *cmd;
6874 NK_ASSERT(b);
6875 if (!b) return;
6876
6877 b->clip.x = r.x;
6878 b->clip.y = r.y;
6879 b->clip.w = r.w;
6880 b->clip.h = r.h;
6881 cmd = (struct nk_command_scissor*)
6882 nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd));
6883
6884 if (!cmd) return;
6885 cmd->x = (short)r.x;
6886 cmd->y = (short)r.y;
6887 cmd->w = (unsigned short)NK_MAX(0, r.w);
6888 cmd->h = (unsigned short)NK_MAX(0, r.h);
6889}
6890
6891NK_API void
6892nk_stroke_line(struct nk_command_buffer *b, float x0, float y0,
6893 float x1, float y1, float line_thickness, struct nk_color c)
6894{
6895 struct nk_command_line *cmd;
6896 NK_ASSERT(b);
6897 if (!b) return;
6898 cmd = (struct nk_command_line*)
6899 nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd));
6900 if (!cmd) return;
6901 cmd->line_thickness = (unsigned short)line_thickness;
6902 cmd->begin.x = (short)x0;
6903 cmd->begin.y = (short)y0;
6904 cmd->end.x = (short)x1;
6905 cmd->end.y = (short)y1;
6906 cmd->color = c;
6907}
6908
6909NK_API void
6910nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay,
6911 float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y,
6912 float bx, float by, float line_thickness, struct nk_color col)
6913{
6914 struct nk_command_curve *cmd;
6915 NK_ASSERT(b);
6916 if (!b || col.a == 0) return;
6917
6918 cmd = (struct nk_command_curve*)
6919 nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd));
6920 if (!cmd) return;
6921 cmd->line_thickness = (unsigned short)line_thickness;
6922 cmd->begin.x = (short)ax;
6923 cmd->begin.y = (short)ay;
6924 cmd->ctrl[0].x = (short)ctrl0x;
6925 cmd->ctrl[0].y = (short)ctrl0y;
6926 cmd->ctrl[1].x = (short)ctrl1x;
6927 cmd->ctrl[1].y = (short)ctrl1y;
6928 cmd->end.x = (short)bx;
6929 cmd->end.y = (short)by;
6930 cmd->color = col;
6931}
6932
6933NK_API void
6934nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect,
6935 float rounding, float line_thickness, struct nk_color c)
6936{
6937 struct nk_command_rect *cmd;
6938 NK_ASSERT(b);
6939 if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return;
6940 if (b->use_clipping) {
6941 const struct nk_rect *clip = &b->clip;
6942 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
6943 clip->x, clip->y, clip->w, clip->h)) return;
6944 }
6945
6946 cmd = (struct nk_command_rect*)
6947 nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd));
6948 if (!cmd) return;
6949 cmd->rounding = (unsigned short)rounding;
6950 cmd->line_thickness = (unsigned short)line_thickness;
6951 cmd->x = (short)rect.x;
6952 cmd->y = (short)rect.y;
6953 cmd->w = (unsigned short)NK_MAX(0, rect.w);
6954 cmd->h = (unsigned short)NK_MAX(0, rect.h);
6955 cmd->color = c;
6956}
6957
6958NK_API void
6959nk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect,
6960 float rounding, struct nk_color c)
6961{
6962 struct nk_command_rect_filled *cmd;
6963 NK_ASSERT(b);
6964 if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return;
6965 if (b->use_clipping) {
6966 const struct nk_rect *clip = &b->clip;
6967 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
6968 clip->x, clip->y, clip->w, clip->h)) return;
6969 }
6970
6971 cmd = (struct nk_command_rect_filled*)
6972 nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd));
6973 if (!cmd) return;
6974 cmd->rounding = (unsigned short)rounding;
6975 cmd->x = (short)rect.x;
6976 cmd->y = (short)rect.y;
6977 cmd->w = (unsigned short)NK_MAX(0, rect.w);
6978 cmd->h = (unsigned short)NK_MAX(0, rect.h);
6979 cmd->color = c;
6980}
6981
6982NK_API void
6983nk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect,
6984 struct nk_color left, struct nk_color top, struct nk_color right,
6985 struct nk_color bottom)
6986{
6987 struct nk_command_rect_multi_color *cmd;
6988 NK_ASSERT(b);
6989 if (!b || rect.w == 0 || rect.h == 0) return;
6990 if (b->use_clipping) {
6991 const struct nk_rect *clip = &b->clip;
6992 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
6993 clip->x, clip->y, clip->w, clip->h)) return;
6994 }
6995
6996 cmd = (struct nk_command_rect_multi_color*)
6997 nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd));
6998 if (!cmd) return;
6999 cmd->x = (short)rect.x;
7000 cmd->y = (short)rect.y;
7001 cmd->w = (unsigned short)NK_MAX(0, rect.w);
7002 cmd->h = (unsigned short)NK_MAX(0, rect.h);
7003 cmd->left = left;
7004 cmd->top = top;
7005 cmd->right = right;
7006 cmd->bottom = bottom;
7007}
7008
7009NK_API void
7010nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r,
7011 float line_thickness, struct nk_color c)
7012{
7013 struct nk_command_circle *cmd;
7014 if (!b || r.w == 0 || r.h == 0) return;
7015 if (b->use_clipping) {
7016 const struct nk_rect *clip = &b->clip;
7017 if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
7018 return;
7019 }
7020
7021 cmd = (struct nk_command_circle*)
7022 nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd));
7023 if (!cmd) return;
7024 cmd->line_thickness = (unsigned short)line_thickness;
7025 cmd->x = (short)r.x;
7026 cmd->y = (short)r.y;
7027 cmd->w = (unsigned short)NK_MAX(r.w, 0);
7028 cmd->h = (unsigned short)NK_MAX(r.h, 0);
7029 cmd->color = c;
7030}
7031
7032NK_API void
7033nk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c)
7034{
7035 struct nk_command_circle_filled *cmd;
7036 NK_ASSERT(b);
7037 if (!b || c.a == 0 || r.w == 0 || r.h == 0) return;
7038 if (b->use_clipping) {
7039 const struct nk_rect *clip = &b->clip;
7040 if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
7041 return;
7042 }
7043
7044 cmd = (struct nk_command_circle_filled*)
7045 nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd));
7046 if (!cmd) return;
7047 cmd->x = (short)r.x;
7048 cmd->y = (short)r.y;
7049 cmd->w = (unsigned short)NK_MAX(r.w, 0);
7050 cmd->h = (unsigned short)NK_MAX(r.h, 0);
7051 cmd->color = c;
7052}
7053
7054NK_API void
7055nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
7056 float a_min, float a_max, float line_thickness, struct nk_color c)
7057{
7058 struct nk_command_arc *cmd;
7059 if (!b || c.a == 0) return;
7060 cmd = (struct nk_command_arc*)
7061 nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd));
7062 if (!cmd) return;
7063 cmd->line_thickness = (unsigned short)line_thickness;
7064 cmd->cx = (short)cx;
7065 cmd->cy = (short)cy;
7066 cmd->r = (unsigned short)radius;
7067 cmd->a[0] = a_min;
7068 cmd->a[1] = a_max;
7069 cmd->color = c;
7070}
7071
7072NK_API void
7073nk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
7074 float a_min, float a_max, struct nk_color c)
7075{
7076 struct nk_command_arc_filled *cmd;
7077 NK_ASSERT(b);
7078 if (!b || c.a == 0) return;
7079 cmd = (struct nk_command_arc_filled*)
7080 nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd));
7081 if (!cmd) return;
7082 cmd->cx = (short)cx;
7083 cmd->cy = (short)cy;
7084 cmd->r = (unsigned short)radius;
7085 cmd->a[0] = a_min;
7086 cmd->a[1] = a_max;
7087 cmd->color = c;
7088}
7089
7090NK_API void
7091nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
7092 float y1, float x2, float y2, float line_thickness, struct nk_color c)
7093{
7094 struct nk_command_triangle *cmd;
7095 NK_ASSERT(b);
7096 if (!b || c.a == 0) return;
7097 if (b->use_clipping) {
7098 const struct nk_rect *clip = &b->clip;
7099 if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
7100 !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
7101 !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
7102 return;
7103 }
7104
7105 cmd = (struct nk_command_triangle*)
7106 nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd));
7107 if (!cmd) return;
7108 cmd->line_thickness = (unsigned short)line_thickness;
7109 cmd->a.x = (short)x0;
7110 cmd->a.y = (short)y0;
7111 cmd->b.x = (short)x1;
7112 cmd->b.y = (short)y1;
7113 cmd->c.x = (short)x2;
7114 cmd->c.y = (short)y2;
7115 cmd->color = c;
7116}
7117
7118NK_API void
7119nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
7120 float y1, float x2, float y2, struct nk_color c)
7121{
7122 struct nk_command_triangle_filled *cmd;
7123 NK_ASSERT(b);
7124 if (!b || c.a == 0) return;
7125 if (!b) return;
7126 if (b->use_clipping) {
7127 const struct nk_rect *clip = &b->clip;
7128 if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
7129 !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
7130 !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
7131 return;
7132 }
7133
7134 cmd = (struct nk_command_triangle_filled*)
7135 nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd));
7136 if (!cmd) return;
7137 cmd->a.x = (short)x0;
7138 cmd->a.y = (short)y0;
7139 cmd->b.x = (short)x1;
7140 cmd->b.y = (short)y1;
7141 cmd->c.x = (short)x2;
7142 cmd->c.y = (short)y2;
7143 cmd->color = c;
7144}
7145
7146NK_API void
7147nk_stroke_polygon(struct nk_command_buffer *b, float *points, int point_count,
7148 float line_thickness, struct nk_color col)
7149{
7150 int i;
7151 nk_size size = 0;
7152 struct nk_command_polygon *cmd;
7153
7154 NK_ASSERT(b);
7155 if (!b || col.a == 0) return;
7156 size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
7157 cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size);
7158 if (!cmd) return;
7159 cmd->color = col;
7160 cmd->line_thickness = (unsigned short)line_thickness;
7161 cmd->point_count = (unsigned short)point_count;
7162 for (i = 0; i < point_count; ++i) {
7163 cmd->points[i].x = (short)points[i*2];
7164 cmd->points[i].y = (short)points[i*2+1];
7165 }
7166}
7167
7168NK_API void
7169nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count,
7170 struct nk_color col)
7171{
7172 int i;
7173 nk_size size = 0;
7174 struct nk_command_polygon_filled *cmd;
7175
7176 NK_ASSERT(b);
7177 if (!b || col.a == 0) return;
7178 size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
7179 cmd = (struct nk_command_polygon_filled*)
7180 nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size);
7181 if (!cmd) return;
7182 cmd->color = col;
7183 cmd->point_count = (unsigned short)point_count;
7184 for (i = 0; i < point_count; ++i) {
7185 cmd->points[i].x = (short)points[i*2+0];
7186 cmd->points[i].y = (short)points[i*2+1];
7187 }
7188}
7189
7190NK_API void
7191nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count,
7192 float line_thickness, struct nk_color col)
7193{
7194 int i;
7195 nk_size size = 0;
7196 struct nk_command_polyline *cmd;
7197
7198 NK_ASSERT(b);
7199 if (!b || col.a == 0) return;
7200 size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
7201 cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size);
7202 if (!cmd) return;
7203 cmd->color = col;
7204 cmd->point_count = (unsigned short)point_count;
7205 cmd->line_thickness = (unsigned short)line_thickness;
7206 for (i = 0; i < point_count; ++i) {
7207 cmd->points[i].x = (short)points[i*2];
7208 cmd->points[i].y = (short)points[i*2+1];
7209 }
7210}
7211
7212NK_API void
7213nk_draw_image(struct nk_command_buffer *b, struct nk_rect r,
7214 const struct nk_image *img, struct nk_color col)
7215{
7216 struct nk_command_image *cmd;
7217 NK_ASSERT(b);
7218 if (!b) return;
7219 if (b->use_clipping) {
7220 const struct nk_rect *c = &b->clip;
7221 if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
7222 return;
7223 }
7224
7225 cmd = (struct nk_command_image*)
7226 nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd));
7227 if (!cmd) return;
7228 cmd->x = (short)r.x;
7229 cmd->y = (short)r.y;
7230 cmd->w = (unsigned short)NK_MAX(0, r.w);
7231 cmd->h = (unsigned short)NK_MAX(0, r.h);
7232 cmd->img = *img;
7233 cmd->col = col;
7234}
7235
7236NK_API void
7237nk_push_custom(struct nk_command_buffer *b, struct nk_rect r,
7238 nk_command_custom_callback cb, nk_handle usr)
7239{
7240 struct nk_command_custom *cmd;
7241 NK_ASSERT(b);
7242 if (!b) return;
7243 if (b->use_clipping) {
7244 const struct nk_rect *c = &b->clip;
7245 if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
7246 return;
7247 }
7248
7249 cmd = (struct nk_command_custom*)
7250 nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd));
7251 if (!cmd) return;
7252 cmd->x = (short)r.x;
7253 cmd->y = (short)r.y;
7254 cmd->w = (unsigned short)NK_MAX(0, r.w);
7255 cmd->h = (unsigned short)NK_MAX(0, r.h);
7256 cmd->callback_data = usr;
7257 cmd->callback = cb;
7258}
7259
7260NK_API void
7261nk_draw_text(struct nk_command_buffer *b, struct nk_rect r,
7262 const char *string, int length, const struct nk_user_font *font,
7263 struct nk_color bg, struct nk_color fg)
7264{
7265 float text_width = 0;
7266 struct nk_command_text *cmd;
7267
7268 NK_ASSERT(b);
7269 NK_ASSERT(font);
7270 if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return;
7271 if (b->use_clipping) {
7272 const struct nk_rect *c = &b->clip;
7273 if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
7274 return;
7275 }
7276
7277 /* make sure text fits inside bounds */
7278 text_width = font->width(font->userdata, font->height, string, length);
7279 if (text_width > r.w){
7280 int glyphs = 0;
7281 float txt_width = (float)text_width;
7282 length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0);
7283 }
7284
7285 if (!length) return;
7286 cmd = (struct nk_command_text*)
7287 nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1));
7288 if (!cmd) return;
7289 cmd->x = (short)r.x;
7290 cmd->y = (short)r.y;
7291 cmd->w = (unsigned short)r.w;
7292 cmd->h = (unsigned short)r.h;
7293 cmd->background = bg;
7294 cmd->foreground = fg;
7295 cmd->font = font;
7296 cmd->length = length;
7297 cmd->height = font->height;
7298 NK_MEMCPY(cmd->string, string, (nk_size)length);
7299 cmd->string[length] = '\0';
7300}
7301
7302/* ==============================================================
7303 *
7304 * DRAW LIST
7305 *
7306 * ===============================================================*/
7307#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
7308NK_API void
7309nk_draw_list_init(struct nk_draw_list *list)
7310{
7311 nk_size i = 0;
7312 NK_ASSERT(list);
7313 if (!list) return;
7314 nk_zero(list, sizeof(*list));
7315 for (i = 0; i < NK_LEN(list->circle_vtx); ++i) {
7316 const float a = ((float)i / (float)NK_LEN(list->circle_vtx)) * 2 * NK_PI;
7317 list->circle_vtx[i].x = (float)NK_COS(a);
7318 list->circle_vtx[i].y = (float)NK_SIN(a);
7319 }
7320}
7321
7322NK_API void
7323nk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config,
7324 struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements)
7325{
7326 NK_ASSERT(canvas);
7327 NK_ASSERT(config);
7328 NK_ASSERT(cmds);
7329 NK_ASSERT(vertices);
7330 NK_ASSERT(elements);
7331 if (!canvas || !config || !cmds || !vertices || !elements)
7332 return;
7333
7334 canvas->buffer = cmds;
7335 canvas->config = *config;
7336 canvas->elements = elements;
7337 canvas->vertices = vertices;
7338 canvas->clip_rect = nk_null_rect;
7339}
7340
7341NK_API const struct nk_draw_command*
7342nk__draw_list_begin(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)
7343{
7344 nk_byte *memory;
7345 nk_size offset;
7346 const struct nk_draw_command *cmd;
7347
7348 NK_ASSERT(buffer);
7349 if (!buffer || !buffer->size || !canvas->cmd_count)
7350 return 0;
7351
7352 memory = (nk_byte*)buffer->memory.ptr;
7353 offset = buffer->memory.size - canvas->cmd_offset;
7354 cmd = nk_ptr_add(const struct nk_draw_command, memory, offset);
7355 return cmd;
7356}
7357
7358NK_API const struct nk_draw_command*
7359nk__draw_list_end(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)
7360{
7361 nk_size size;
7362 nk_size offset;
7363 nk_byte *memory;
7364 const struct nk_draw_command *end;
7365
7366 NK_ASSERT(buffer);
7367 NK_ASSERT(canvas);
7368 if (!buffer || !canvas)
7369 return 0;
7370
7371 memory = (nk_byte*)buffer->memory.ptr;
7372 size = buffer->memory.size;
7373 offset = size - canvas->cmd_offset;
7374 end = nk_ptr_add(const struct nk_draw_command, memory, offset);
7375 end -= (canvas->cmd_count-1);
7376 return end;
7377}
7378
7379NK_API const struct nk_draw_command*
7380nk__draw_list_next(const struct nk_draw_command *cmd,
7381 const struct nk_buffer *buffer, const struct nk_draw_list *canvas)
7382{
7383 const struct nk_draw_command *end;
7384 NK_ASSERT(buffer);
7385 NK_ASSERT(canvas);
7386 if (!cmd || !buffer || !canvas)
7387 return 0;
7388
7389 end = nk__draw_list_end(canvas, buffer);
7390 if (cmd <= end) return 0;
7391 return (cmd-1);
7392}
7393
7394NK_API void
7395nk_draw_list_clear(struct nk_draw_list *list)
7396{
7397 NK_ASSERT(list);
7398 if (!list) return;
7399 if (list->buffer)
7400 nk_buffer_clear(list->buffer);
7401 if (list->vertices)
7402 nk_buffer_clear(list->vertices);
7403 if (list->elements)
7404 nk_buffer_clear(list->elements);
7405
7406 list->element_count = 0;
7407 list->vertex_count = 0;
7408 list->cmd_offset = 0;
7409 list->cmd_count = 0;
7410 list->path_count = 0;
7411 list->vertices = 0;
7412 list->elements = 0;
7413 list->clip_rect = nk_null_rect;
7414}
7415
7416NK_INTERN struct nk_vec2*
7417nk_draw_list_alloc_path(struct nk_draw_list *list, int count)
7418{
7419 struct nk_vec2 *points;
7420 NK_STORAGE const nk_size point_align = NK_ALIGNOF(struct nk_vec2);
7421 NK_STORAGE const nk_size point_size = sizeof(struct nk_vec2);
7422 points = (struct nk_vec2*)
7423 nk_buffer_alloc(list->buffer, NK_BUFFER_FRONT,
7424 point_size * (nk_size)count, point_align);
7425
7426 if (!points) return 0;
7427 if (!list->path_offset) {
7428 void *memory = nk_buffer_memory(list->buffer);
7429 list->path_offset = (unsigned int)((nk_byte*)points - (nk_byte*)memory);
7430 }
7431 list->path_count += (unsigned int)count;
7432 return points;
7433}
7434
7435NK_INTERN struct nk_vec2
7436nk_draw_list_path_last(struct nk_draw_list *list)
7437{
7438 void *memory;
7439 struct nk_vec2 *point;
7440 NK_ASSERT(list->path_count);
7441 memory = nk_buffer_memory(list->buffer);
7442 point = nk_ptr_add(struct nk_vec2, memory, list->path_offset);
7443 point += (list->path_count-1);
7444 return *point;
7445}
7446
7447NK_INTERN struct nk_draw_command*
7448nk_draw_list_push_command(struct nk_draw_list *list, struct nk_rect clip,
7449 nk_handle texture)
7450{
7451 NK_STORAGE const nk_size cmd_align = NK_ALIGNOF(struct nk_draw_command);
7452 NK_STORAGE const nk_size cmd_size = sizeof(struct nk_draw_command);
7453 struct nk_draw_command *cmd;
7454
7455 NK_ASSERT(list);
7456 cmd = (struct nk_draw_command*)
7457 nk_buffer_alloc(list->buffer, NK_BUFFER_BACK, cmd_size, cmd_align);
7458
7459 if (!cmd) return 0;
7460 if (!list->cmd_count) {
7461 nk_byte *memory = (nk_byte*)nk_buffer_memory(list->buffer);
7462 nk_size total = nk_buffer_total(list->buffer);
7463 memory = nk_ptr_add(nk_byte, memory, total);
7464 list->cmd_offset = (nk_size)(memory - (nk_byte*)cmd);
7465 }
7466
7467 cmd->elem_count = 0;
7468 cmd->clip_rect = clip;
7469 cmd->texture = texture;
7470#ifdef NK_INCLUDE_COMMAND_USERDATA
7471 cmd->userdata = list->userdata;
7472#endif
7473
7474 list->cmd_count++;
7475 list->clip_rect = clip;
7476 return cmd;
7477}
7478
7479NK_INTERN struct nk_draw_command*
7480nk_draw_list_command_last(struct nk_draw_list *list)
7481{
7482 void *memory;
7483 nk_size size;
7484 struct nk_draw_command *cmd;
7485 NK_ASSERT(list->cmd_count);
7486
7487 memory = nk_buffer_memory(list->buffer);
7488 size = nk_buffer_total(list->buffer);
7489 cmd = nk_ptr_add(struct nk_draw_command, memory, size - list->cmd_offset);
7490 return (cmd - (list->cmd_count-1));
7491}
7492
7493NK_INTERN void
7494nk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect)
7495{
7496 NK_ASSERT(list);
7497 if (!list) return;
7498 if (!list->cmd_count) {
7499 nk_draw_list_push_command(list, rect, list->config.null.texture);
7500 } else {
7501 struct nk_draw_command *prev = nk_draw_list_command_last(list);
7502 if (prev->elem_count == 0)
7503 prev->clip_rect = rect;
7504 nk_draw_list_push_command(list, rect, prev->texture);
7505 }
7506}
7507
7508NK_INTERN void
7509nk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture)
7510{
7511 NK_ASSERT(list);
7512 if (!list) return;
7513 if (!list->cmd_count) {
7514 nk_draw_list_push_command(list, nk_null_rect, texture);
7515 } else {
7516 struct nk_draw_command *prev = nk_draw_list_command_last(list);
7517 if (prev->elem_count == 0)
7518 prev->texture = texture;
7519 else if (prev->texture.id != texture.id)
7520 nk_draw_list_push_command(list, prev->clip_rect, texture);
7521 }
7522}
7523
7524#ifdef NK_INCLUDE_COMMAND_USERDATA
7525NK_API void
7526nk_draw_list_push_userdata(struct nk_draw_list *list, nk_handle userdata)
7527{
7528 list->userdata = userdata;
7529}
7530#endif
7531
7532NK_INTERN void*
7533nk_draw_list_alloc_vertices(struct nk_draw_list *list, nk_size count)
7534{
7535 void *vtx;
7536 NK_ASSERT(list);
7537 if (!list) return 0;
7538 vtx = nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT,
7539 list->config.vertex_size*count, list->config.vertex_alignment);
7540 if (!vtx) return 0;
7541 list->vertex_count += (unsigned int)count;
7542 return vtx;
7543}
7544
7545NK_INTERN nk_draw_index*
7546nk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count)
7547{
7548 nk_draw_index *ids;
7549 struct nk_draw_command *cmd;
7550 NK_STORAGE const nk_size elem_align = NK_ALIGNOF(nk_draw_index);
7551 NK_STORAGE const nk_size elem_size = sizeof(nk_draw_index);
7552 NK_ASSERT(list);
7553 if (!list) return 0;
7554
7555 ids = (nk_draw_index*)
7556 nk_buffer_alloc(list->elements, NK_BUFFER_FRONT, elem_size*count, elem_align);
7557 if (!ids) return 0;
7558 cmd = nk_draw_list_command_last(list);
7559 list->element_count += (unsigned int)count;
7560 cmd->elem_count += (unsigned int)count;
7561 return ids;
7562}
7563
7564static int
7565nk_draw_vertex_layout_element_is_end_of_layout(
7566 const struct nk_draw_vertex_layout_element *element)
7567{
7568 return (element->attribute == NK_VERTEX_ATTRIBUTE_COUNT ||
7569 element->format == NK_FORMAT_COUNT);
7570}
7571
7572static void
7573nk_draw_vertex_color(void *attribute, const float *values,
7574 enum nk_draw_vertex_layout_format format)
7575{
7576 /* if this triggers you tried to provide a value format for a color */
7577 NK_ASSERT(format >= NK_FORMAT_COLOR_BEGIN);
7578 NK_ASSERT(format <= NK_FORMAT_COLOR_END);
7579 if (format < NK_FORMAT_COLOR_BEGIN || format > NK_FORMAT_COLOR_END) return;
7580
7581 switch (format) {
7582 default: NK_ASSERT(0 && "Invalid vertex layout color format"); break;
7583 case NK_FORMAT_R8G8B8A8:
7584 case NK_FORMAT_R8G8B8: {
7585 struct nk_color col = nk_rgba_fv(values);
7586 NK_MEMCPY(attribute, &col.r, sizeof(col));
7587 } break;
7588 case NK_FORMAT_R16G15B16: {
7589 nk_ushort col[3];
7590 col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX);
7591 col[1] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[1] * NK_USHORT_MAX, NK_USHORT_MAX);
7592 col[2] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[2] * NK_USHORT_MAX, NK_USHORT_MAX);
7593 NK_MEMCPY(attribute, col, sizeof(col));
7594 } break;
7595 case NK_FORMAT_R16G15B16A16: {
7596 nk_ushort col[4];
7597 col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX);
7598 col[1] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[1] * NK_USHORT_MAX, NK_USHORT_MAX);
7599 col[2] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[2] * NK_USHORT_MAX, NK_USHORT_MAX);
7600 col[3] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[3] * NK_USHORT_MAX, NK_USHORT_MAX);
7601 NK_MEMCPY(attribute, col, sizeof(col));
7602 } break;
7603 case NK_FORMAT_R32G32B32: {
7604 nk_uint col[3];
7605 col[0] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[0] * NK_UINT_MAX, NK_UINT_MAX);
7606 col[1] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[1] * NK_UINT_MAX, NK_UINT_MAX);
7607 col[2] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[2] * NK_UINT_MAX, NK_UINT_MAX);
7608 NK_MEMCPY(attribute, col, sizeof(col));
7609 } break;
7610 case NK_FORMAT_R32G32B32A32: {
7611 nk_uint col[4];
7612 col[0] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[0] * NK_UINT_MAX, NK_UINT_MAX);
7613 col[1] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[1] * NK_UINT_MAX, NK_UINT_MAX);
7614 col[2] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[2] * NK_UINT_MAX, NK_UINT_MAX);
7615 col[3] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[3] * NK_UINT_MAX, NK_UINT_MAX);
7616 NK_MEMCPY(attribute, col, sizeof(col));
7617 } break;
7618 case NK_FORMAT_R32G32B32A32_FLOAT:
7619 NK_MEMCPY(attribute, values, sizeof(float)*4);
7620 break;
7621 case NK_FORMAT_R32G32B32A32_DOUBLE: {
7622 double col[4];
7623 col[0] = (double)NK_SATURATE(values[0]);
7624 col[1] = (double)NK_SATURATE(values[1]);
7625 col[2] = (double)NK_SATURATE(values[2]);
7626 col[3] = (double)NK_SATURATE(values[3]);
7627 NK_MEMCPY(attribute, col, sizeof(col));
7628 } break;
7629 case NK_FORMAT_RGB32:
7630 case NK_FORMAT_RGBA32: {
7631 struct nk_color col = nk_rgba_fv(values);
7632 nk_uint color = nk_color_u32(col);
7633 NK_MEMCPY(attribute, &color, sizeof(color));
7634 } break;
7635 }
7636}
7637
7638static void
7639nk_draw_vertex_element(void *dst, const float *values, int value_count,
7640 enum nk_draw_vertex_layout_format format)
7641{
7642 int value_index;
7643 void *attribute = dst;
7644 /* if this triggers you tried to provide a color format for a value */
7645 NK_ASSERT(format < NK_FORMAT_COLOR_BEGIN);
7646 if (format >= NK_FORMAT_COLOR_BEGIN && format <= NK_FORMAT_COLOR_END) return;
7647 for (value_index = 0; value_index < value_count; ++value_index) {
7648 switch (format) {
7649 default: NK_ASSERT(0 && "invalid vertex layout format"); break;
7650 case NK_FORMAT_SCHAR: {
7651 char value = (char)NK_CLAMP(NK_SCHAR_MIN, values[value_index], NK_SCHAR_MAX);
7652 NK_MEMCPY(attribute, &value, sizeof(value));
7653 attribute = (void*)((char*)attribute + sizeof(char));
7654 } break;
7655 case NK_FORMAT_SSHORT: {
7656 nk_short value = (nk_short)NK_CLAMP(NK_SSHORT_MIN, values[value_index], NK_SSHORT_MAX);
7657 NK_MEMCPY(attribute, &value, sizeof(value));
7658 attribute = (void*)((char*)attribute + sizeof(value));
7659 } break;
7660 case NK_FORMAT_SINT: {
7661 nk_int value = (nk_int)NK_CLAMP(NK_SINT_MIN, values[value_index], NK_SINT_MAX);
7662 NK_MEMCPY(attribute, &value, sizeof(value));
7663 attribute = (void*)((char*)attribute + sizeof(nk_int));
7664 } break;
7665 case NK_FORMAT_UCHAR: {
7666 unsigned char value = (unsigned char)NK_CLAMP(NK_UCHAR_MIN, values[value_index], NK_UCHAR_MAX);
7667 NK_MEMCPY(attribute, &value, sizeof(value));
7668 attribute = (void*)((char*)attribute + sizeof(unsigned char));
7669 } break;
7670 case NK_FORMAT_USHORT: {
7671 nk_ushort value = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[value_index], NK_USHORT_MAX);
7672 NK_MEMCPY(attribute, &value, sizeof(value));
7673 attribute = (void*)((char*)attribute + sizeof(value));
7674 } break;
7675 case NK_FORMAT_UINT: {
7676 nk_uint value = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[value_index], NK_UINT_MAX);
7677 NK_MEMCPY(attribute, &value, sizeof(value));
7678 attribute = (void*)((char*)attribute + sizeof(nk_uint));
7679 } break;
7680 case NK_FORMAT_FLOAT:
7681 NK_MEMCPY(attribute, &values[value_index], sizeof(values[value_index]));
7682 attribute = (void*)((char*)attribute + sizeof(float));
7683 break;
7684 case NK_FORMAT_DOUBLE: {
7685 double value = (double)values[value_index];
7686 NK_MEMCPY(attribute, &value, sizeof(value));
7687 attribute = (void*)((char*)attribute + sizeof(double));
7688 } break;
7689 }
7690 }
7691}
7692
7693NK_INTERN void*
7694nk_draw_vertex(void *dst, const struct nk_convert_config *config,
7695 struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color)
7696{
7697 void *result = (void*)((char*)dst + config->vertex_size);
7698 const struct nk_draw_vertex_layout_element *elem_iter = config->vertex_layout;
7699 while (!nk_draw_vertex_layout_element_is_end_of_layout(elem_iter)) {
7700 void *address = (void*)((char*)dst + elem_iter->offset);
7701 switch (elem_iter->attribute) {
7702 case NK_VERTEX_ATTRIBUTE_COUNT:
7703 default: NK_ASSERT(0 && "wrong element attribute");
7704 case NK_VERTEX_POSITION: nk_draw_vertex_element(address, &pos.x, 2, elem_iter->format); break;
7705 case NK_VERTEX_TEXCOORD: nk_draw_vertex_element(address, &uv.x, 2, elem_iter->format); break;
7706 case NK_VERTEX_COLOR: nk_draw_vertex_color(address, &color.r, elem_iter->format); break;
7707 }
7708 elem_iter++;
7709 }
7710 return result;
7711}
7712
7713NK_API void
7714nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *points,
7715 const unsigned int points_count, struct nk_color color, enum nk_draw_list_stroke closed,
7716 float thickness, enum nk_anti_aliasing aliasing)
7717{
7718 nk_size count;
7719 int thick_line;
7720 struct nk_colorf col;
7721 struct nk_colorf col_trans;
7722 NK_ASSERT(list);
7723 if (!list || points_count < 2) return;
7724
7725 color.a = (nk_byte)((float)color.a * list->config.global_alpha);
7726 count = points_count;
7727 if (!closed) count = points_count-1;
7728 thick_line = thickness > 1.0f;
7729
7730#ifdef NK_INCLUDE_COMMAND_USERDATA
7731 nk_draw_list_push_userdata(list, list->userdata);
7732#endif
7733
7734 color.a = (nk_byte)((float)color.a * list->config.global_alpha);
7735 nk_color_fv(&col.r, color);
7736 col_trans = col;
7737 col_trans.a = 0;
7738
7739 if (aliasing == NK_ANTI_ALIASING_ON) {
7740 /* ANTI-ALIASED STROKE */
7741 const float AA_SIZE = 1.0f;
7742 NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);
7743 NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);
7744
7745 /* allocate vertices and elements */
7746 nk_size i1 = 0;
7747 nk_size vertex_offset;
7748 nk_size index = list->vertex_count;
7749
7750 const nk_size idx_count = (thick_line) ? (count * 18) : (count * 12);
7751 const nk_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3);
7752
7753 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
7754 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
7755
7756 nk_size size;
7757 struct nk_vec2 *normals, *temp;
7758 if (!vtx || !ids) return;
7759
7760 /* temporary allocate normals + points */
7761 vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);
7762 nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);
7763 size = pnt_size * ((thick_line) ? 5 : 3) * points_count;
7764 normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);
7765 NK_ASSERT(normals);
7766 if (!normals) return;
7767 temp = normals + points_count;
7768
7769 /* make sure vertex pointer is still correct */
7770 vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);
7771
7772 /* calculate normals */
7773 for (i1 = 0; i1 < count; ++i1) {
7774 const nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);
7775 struct nk_vec2 diff = nk_vec2_sub(points[i2], points[i1]);
7776 float len;
7777
7778 /* vec2 inverted length */
7779 len = nk_vec2_len_sqr(diff);
7780 if (len != 0.0f)
7781 len = nk_inv_sqrt(len);
7782 else len = 1.0f;
7783
7784 diff = nk_vec2_muls(diff, len);
7785 normals[i1].x = diff.y;
7786 normals[i1].y = -diff.x;
7787 }
7788
7789 if (!closed)
7790 normals[points_count-1] = normals[points_count-2];
7791
7792 if (!thick_line) {
7793 nk_size idx1, i;
7794 if (!closed) {
7795 struct nk_vec2 d;
7796 temp[0] = nk_vec2_add(points[0], nk_vec2_muls(normals[0], AA_SIZE));
7797 temp[1] = nk_vec2_sub(points[0], nk_vec2_muls(normals[0], AA_SIZE));
7798 d = nk_vec2_muls(normals[points_count-1], AA_SIZE);
7799 temp[(points_count-1) * 2 + 0] = nk_vec2_add(points[points_count-1], d);
7800 temp[(points_count-1) * 2 + 1] = nk_vec2_sub(points[points_count-1], d);
7801 }
7802
7803 /* fill elements */
7804 idx1 = index;
7805 for (i1 = 0; i1 < count; i1++) {
7806 struct nk_vec2 dm;
7807 float dmr2;
7808 nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);
7809 nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 3);
7810
7811 /* average normals */
7812 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);
7813 dmr2 = dm.x * dm.x + dm.y* dm.y;
7814 if (dmr2 > 0.000001f) {
7815 float scale = 1.0f/dmr2;
7816 scale = NK_MIN(100.0f, scale);
7817 dm = nk_vec2_muls(dm, scale);
7818 }
7819
7820 dm = nk_vec2_muls(dm, AA_SIZE);
7821 temp[i2*2+0] = nk_vec2_add(points[i2], dm);
7822 temp[i2*2+1] = nk_vec2_sub(points[i2], dm);
7823
7824 ids[0] = (nk_draw_index)(idx2 + 0); ids[1] = (nk_draw_index)(idx1+0);
7825 ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);
7826 ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+0);
7827 ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);
7828 ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);
7829 ids[10]= (nk_draw_index)(idx2 + 0); ids[11]= (nk_draw_index)(idx2+1);
7830 ids += 12;
7831 idx1 = idx2;
7832 }
7833
7834 /* fill vertices */
7835 for (i = 0; i < points_count; ++i) {
7836 const struct nk_vec2 uv = list->config.null.uv;
7837 vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col);
7838 vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans);
7839 vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans);
7840 }
7841 } else {
7842 nk_size idx1, i;
7843 const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
7844 if (!closed) {
7845 struct nk_vec2 d1 = nk_vec2_muls(normals[0], half_inner_thickness + AA_SIZE);
7846 struct nk_vec2 d2 = nk_vec2_muls(normals[0], half_inner_thickness);
7847
7848 temp[0] = nk_vec2_add(points[0], d1);
7849 temp[1] = nk_vec2_add(points[0], d2);
7850 temp[2] = nk_vec2_sub(points[0], d2);
7851 temp[3] = nk_vec2_sub(points[0], d1);
7852
7853 d1 = nk_vec2_muls(normals[points_count-1], half_inner_thickness + AA_SIZE);
7854 d2 = nk_vec2_muls(normals[points_count-1], half_inner_thickness);
7855
7856 temp[(points_count-1)*4+0] = nk_vec2_add(points[points_count-1], d1);
7857 temp[(points_count-1)*4+1] = nk_vec2_add(points[points_count-1], d2);
7858 temp[(points_count-1)*4+2] = nk_vec2_sub(points[points_count-1], d2);
7859 temp[(points_count-1)*4+3] = nk_vec2_sub(points[points_count-1], d1);
7860 }
7861
7862 /* add all elements */
7863 idx1 = index;
7864 for (i1 = 0; i1 < count; ++i1) {
7865 struct nk_vec2 dm_out, dm_in;
7866 const nk_size i2 = ((i1+1) == points_count) ? 0: (i1 + 1);
7867 nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 4);
7868
7869 /* average normals */
7870 struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);
7871 float dmr2 = dm.x * dm.x + dm.y* dm.y;
7872 if (dmr2 > 0.000001f) {
7873 float scale = 1.0f/dmr2;
7874 scale = NK_MIN(100.0f, scale);
7875 dm = nk_vec2_muls(dm, scale);
7876 }
7877
7878 dm_out = nk_vec2_muls(dm, ((half_inner_thickness) + AA_SIZE));
7879 dm_in = nk_vec2_muls(dm, half_inner_thickness);
7880 temp[i2*4+0] = nk_vec2_add(points[i2], dm_out);
7881 temp[i2*4+1] = nk_vec2_add(points[i2], dm_in);
7882 temp[i2*4+2] = nk_vec2_sub(points[i2], dm_in);
7883 temp[i2*4+3] = nk_vec2_sub(points[i2], dm_out);
7884
7885 /* add indexes */
7886 ids[0] = (nk_draw_index)(idx2 + 1); ids[1] = (nk_draw_index)(idx1+1);
7887 ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);
7888 ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+1);
7889 ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);
7890 ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);
7891 ids[10]= (nk_draw_index)(idx2 + 0); ids[11] = (nk_draw_index)(idx2+1);
7892 ids[12]= (nk_draw_index)(idx2 + 2); ids[13] = (nk_draw_index)(idx1+2);
7893 ids[14]= (nk_draw_index)(idx1 + 3); ids[15] = (nk_draw_index)(idx1+3);
7894 ids[16]= (nk_draw_index)(idx2 + 3); ids[17] = (nk_draw_index)(idx2+2);
7895 ids += 18;
7896 idx1 = idx2;
7897 }
7898
7899 /* add vertices */
7900 for (i = 0; i < points_count; ++i) {
7901 const struct nk_vec2 uv = list->config.null.uv;
7902 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans);
7903 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col);
7904 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col);
7905 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+3], uv, col_trans);
7906 }
7907 }
7908 /* free temporary normals + points */
7909 nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);
7910 } else {
7911 /* NON ANTI-ALIASED STROKE */
7912 nk_size i1 = 0;
7913 nk_size idx = list->vertex_count;
7914 const nk_size idx_count = count * 6;
7915 const nk_size vtx_count = count * 4;
7916 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
7917 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
7918 if (!vtx || !ids) return;
7919
7920 for (i1 = 0; i1 < count; ++i1) {
7921 float dx, dy;
7922 const struct nk_vec2 uv = list->config.null.uv;
7923 const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1;
7924 const struct nk_vec2 p1 = points[i1];
7925 const struct nk_vec2 p2 = points[i2];
7926 struct nk_vec2 diff = nk_vec2_sub(p2, p1);
7927 float len;
7928
7929 /* vec2 inverted length */
7930 len = nk_vec2_len_sqr(diff);
7931 if (len != 0.0f)
7932 len = nk_inv_sqrt(len);
7933 else len = 1.0f;
7934 diff = nk_vec2_muls(diff, len);
7935
7936 /* add vertices */
7937 dx = diff.x * (thickness * 0.5f);
7938 dy = diff.y * (thickness * 0.5f);
7939
7940 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x + dy, p1.y - dx), uv, col);
7941 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x + dy, p2.y - dx), uv, col);
7942 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x - dy, p2.y + dx), uv, col);
7943 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x - dy, p1.y + dx), uv, col);
7944
7945 ids[0] = (nk_draw_index)(idx+0); ids[1] = (nk_draw_index)(idx+1);
7946 ids[2] = (nk_draw_index)(idx+2); ids[3] = (nk_draw_index)(idx+0);
7947 ids[4] = (nk_draw_index)(idx+2); ids[5] = (nk_draw_index)(idx+3);
7948
7949 ids += 6;
7950 idx += 4;
7951 }
7952 }
7953}
7954
7955NK_API void
7956nk_draw_list_fill_poly_convex(struct nk_draw_list *list,
7957 const struct nk_vec2 *points, const unsigned int points_count,
7958 struct nk_color color, enum nk_anti_aliasing aliasing)
7959{
7960 struct nk_colorf col;
7961 struct nk_colorf col_trans;
7962
7963 NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);
7964 NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);
7965 NK_ASSERT(list);
7966 if (!list || points_count < 3) return;
7967
7968#ifdef NK_INCLUDE_COMMAND_USERDATA
7969 nk_draw_list_push_userdata(list, list->userdata);
7970#endif
7971
7972 color.a = (nk_byte)((float)color.a * list->config.global_alpha);
7973 nk_color_fv(&col.r, color);
7974 col_trans = col;
7975 col_trans.a = 0;
7976
7977 if (aliasing == NK_ANTI_ALIASING_ON) {
7978 nk_size i = 0;
7979 nk_size i0 = 0;
7980 nk_size i1 = 0;
7981
7982 const float AA_SIZE = 1.0f;
7983 nk_size vertex_offset = 0;
7984 nk_size index = list->vertex_count;
7985
7986 const nk_size idx_count = (points_count-2)*3 + points_count*6;
7987 const nk_size vtx_count = (points_count*2);
7988
7989 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
7990 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
7991
7992 nk_size size = 0;
7993 struct nk_vec2 *normals = 0;
7994 unsigned int vtx_inner_idx = (unsigned int)(index + 0);
7995 unsigned int vtx_outer_idx = (unsigned int)(index + 1);
7996 if (!vtx || !ids) return;
7997
7998 /* temporary allocate normals */
7999 vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);
8000 nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);
8001 size = pnt_size * points_count;
8002 normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);
8003 NK_ASSERT(normals);
8004 if (!normals) return;
8005 vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);
8006
8007 /* add elements */
8008 for (i = 2; i < points_count; i++) {
8009 ids[0] = (nk_draw_index)(vtx_inner_idx);
8010 ids[1] = (nk_draw_index)(vtx_inner_idx + ((i-1) << 1));
8011 ids[2] = (nk_draw_index)(vtx_inner_idx + (i << 1));
8012 ids += 3;
8013 }
8014
8015 /* compute normals */
8016 for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {
8017 struct nk_vec2 p0 = points[i0];
8018 struct nk_vec2 p1 = points[i1];
8019 struct nk_vec2 diff = nk_vec2_sub(p1, p0);
8020
8021 /* vec2 inverted length */
8022 float len = nk_vec2_len_sqr(diff);
8023 if (len != 0.0f)
8024 len = nk_inv_sqrt(len);
8025 else len = 1.0f;
8026 diff = nk_vec2_muls(diff, len);
8027
8028 normals[i0].x = diff.y;
8029 normals[i0].y = -diff.x;
8030 }
8031
8032 /* add vertices + indexes */
8033 for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {
8034 const struct nk_vec2 uv = list->config.null.uv;
8035 struct nk_vec2 n0 = normals[i0];
8036 struct nk_vec2 n1 = normals[i1];
8037 struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f);
8038 float dmr2 = dm.x*dm.x + dm.y*dm.y;
8039 if (dmr2 > 0.000001f) {
8040 float scale = 1.0f / dmr2;
8041 scale = NK_MIN(scale, 100.0f);
8042 dm = nk_vec2_muls(dm, scale);
8043 }
8044 dm = nk_vec2_muls(dm, AA_SIZE * 0.5f);
8045
8046 /* add vertices */
8047 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_sub(points[i1], dm), uv, col);
8048 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_add(points[i1], dm), uv, col_trans);
8049
8050 /* add indexes */
8051 ids[0] = (nk_draw_index)(vtx_inner_idx+(i1<<1));
8052 ids[1] = (nk_draw_index)(vtx_inner_idx+(i0<<1));
8053 ids[2] = (nk_draw_index)(vtx_outer_idx+(i0<<1));
8054 ids[3] = (nk_draw_index)(vtx_outer_idx+(i0<<1));
8055 ids[4] = (nk_draw_index)(vtx_outer_idx+(i1<<1));
8056 ids[5] = (nk_draw_index)(vtx_inner_idx+(i1<<1));
8057 ids += 6;
8058 }
8059 /* free temporary normals + points */
8060 nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);
8061 } else {
8062 nk_size i = 0;
8063 nk_size index = list->vertex_count;
8064 const nk_size idx_count = (points_count-2)*3;
8065 const nk_size vtx_count = points_count;
8066 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
8067 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
8068
8069 if (!vtx || !ids) return;
8070 for (i = 0; i < vtx_count; ++i)
8071 vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.null.uv, col);
8072 for (i = 2; i < points_count; ++i) {
8073 ids[0] = (nk_draw_index)index;
8074 ids[1] = (nk_draw_index)(index+ i - 1);
8075 ids[2] = (nk_draw_index)(index+i);
8076 ids += 3;
8077 }
8078 }
8079}
8080
8081NK_API void
8082nk_draw_list_path_clear(struct nk_draw_list *list)
8083{
8084 NK_ASSERT(list);
8085 if (!list) return;
8086 nk_buffer_reset(list->buffer, NK_BUFFER_FRONT);
8087 list->path_count = 0;
8088 list->path_offset = 0;
8089}
8090
8091NK_API void
8092nk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos)
8093{
8094 struct nk_vec2 *points = 0;
8095 struct nk_draw_command *cmd = 0;
8096 NK_ASSERT(list);
8097 if (!list) return;
8098 if (!list->cmd_count)
8099 nk_draw_list_add_clip(list, nk_null_rect);
8100
8101 cmd = nk_draw_list_command_last(list);
8102 if (cmd && cmd->texture.ptr != list->config.null.texture.ptr)
8103 nk_draw_list_push_image(list, list->config.null.texture);
8104
8105 points = nk_draw_list_alloc_path(list, 1);
8106 if (!points) return;
8107 points[0] = pos;
8108}
8109
8110NK_API void
8111nk_draw_list_path_arc_to_fast(struct nk_draw_list *list, struct nk_vec2 center,
8112 float radius, int a_min, int a_max)
8113{
8114 int a = 0;
8115 NK_ASSERT(list);
8116 if (!list) return;
8117 if (a_min <= a_max) {
8118 for (a = a_min; a <= a_max; a++) {
8119 const struct nk_vec2 c = list->circle_vtx[(nk_size)a % NK_LEN(list->circle_vtx)];
8120 const float x = center.x + c.x * radius;
8121 const float y = center.y + c.y * radius;
8122 nk_draw_list_path_line_to(list, nk_vec2(x, y));
8123 }
8124 }
8125}
8126
8127NK_API void
8128nk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center,
8129 float radius, float a_min, float a_max, unsigned int segments)
8130{
8131 unsigned int i = 0;
8132 NK_ASSERT(list);
8133 if (!list) return;
8134 if (radius == 0.0f) return;
8135 for (i = 0; i <= segments; ++i) {
8136 const float a = a_min + ((float)i / ((float)segments) * (a_max - a_min));
8137 const float x = center.x + (float)NK_COS(a) * radius;
8138 const float y = center.y + (float)NK_SIN(a) * radius;
8139 nk_draw_list_path_line_to(list, nk_vec2(x, y));
8140 }
8141}
8142
8143NK_API void
8144nk_draw_list_path_rect_to(struct nk_draw_list *list, struct nk_vec2 a,
8145 struct nk_vec2 b, float rounding)
8146{
8147 float r;
8148 NK_ASSERT(list);
8149 if (!list) return;
8150 r = rounding;
8151 r = NK_MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x));
8152 r = NK_MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y));
8153
8154 if (r == 0.0f) {
8155 nk_draw_list_path_line_to(list, a);
8156 nk_draw_list_path_line_to(list, nk_vec2(b.x,a.y));
8157 nk_draw_list_path_line_to(list, b);
8158 nk_draw_list_path_line_to(list, nk_vec2(a.x,b.y));
8159 } else {
8160 nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, a.y + r), r, 6, 9);
8161 nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, a.y + r), r, 9, 12);
8162 nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, b.y - r), r, 0, 3);
8163 nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, b.y - r), r, 3, 6);
8164 }
8165}
8166
8167NK_API void
8168nk_draw_list_path_curve_to(struct nk_draw_list *list, struct nk_vec2 p2,
8169 struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments)
8170{
8171 float t_step;
8172 unsigned int i_step;
8173 struct nk_vec2 p1;
8174
8175 NK_ASSERT(list);
8176 NK_ASSERT(list->path_count);
8177 if (!list || !list->path_count) return;
8178 num_segments = NK_MAX(num_segments, 1);
8179
8180 p1 = nk_draw_list_path_last(list);
8181 t_step = 1.0f/(float)num_segments;
8182 for (i_step = 1; i_step <= num_segments; ++i_step) {
8183 float t = t_step * (float)i_step;
8184 float u = 1.0f - t;
8185 float w1 = u*u*u;
8186 float w2 = 3*u*u*t;
8187 float w3 = 3*u*t*t;
8188 float w4 = t * t *t;
8189 float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;
8190 float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;
8191 nk_draw_list_path_line_to(list, nk_vec2(x,y));
8192 }
8193}
8194
8195NK_API void
8196nk_draw_list_path_fill(struct nk_draw_list *list, struct nk_color color)
8197{
8198 struct nk_vec2 *points;
8199 NK_ASSERT(list);
8200 if (!list) return;
8201 points = (struct nk_vec2*)nk_buffer_memory(list->buffer);
8202 nk_draw_list_fill_poly_convex(list, points, list->path_count, color, list->config.shape_AA);
8203 nk_draw_list_path_clear(list);
8204}
8205
8206NK_API void
8207nk_draw_list_path_stroke(struct nk_draw_list *list, struct nk_color color,
8208 enum nk_draw_list_stroke closed, float thickness)
8209{
8210 struct nk_vec2 *points;
8211 NK_ASSERT(list);
8212 if (!list) return;
8213 points = (struct nk_vec2*)nk_buffer_memory(list->buffer);
8214 nk_draw_list_stroke_poly_line(list, points, list->path_count, color,
8215 closed, thickness, list->config.line_AA);
8216 nk_draw_list_path_clear(list);
8217}
8218
8219NK_API void
8220nk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a,
8221 struct nk_vec2 b, struct nk_color col, float thickness)
8222{
8223 NK_ASSERT(list);
8224 if (!list || !col.a) return;
8225 nk_draw_list_path_line_to(list, nk_vec2_add(a, nk_vec2(0.5f, 0.5f)));
8226 nk_draw_list_path_line_to(list, nk_vec2_add(b, nk_vec2(0.5f, 0.5f)));
8227 nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness);
8228}
8229
8230NK_API void
8231nk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect,
8232 struct nk_color col, float rounding)
8233{
8234 NK_ASSERT(list);
8235 if (!list || !col.a) return;
8236 nk_draw_list_path_rect_to(list, nk_vec2(rect.x + 0.5f, rect.y + 0.5f),
8237 nk_vec2(rect.x + rect.w + 0.5f, rect.y + rect.h + 0.5f), rounding);
8238 nk_draw_list_path_fill(list, col);
8239}
8240
8241NK_API void
8242nk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect,
8243 struct nk_color col, float rounding, float thickness)
8244{
8245 NK_ASSERT(list);
8246 if (!list || !col.a) return;
8247 nk_draw_list_path_rect_to(list, nk_vec2(rect.x + 0.5f, rect.y + 0.5f),
8248 nk_vec2(rect.x + rect.w + 0.5f, rect.y + rect.h + 0.5f), rounding);
8249 nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);
8250}
8251
8252NK_API void
8253nk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rect,
8254 struct nk_color left, struct nk_color top, struct nk_color right,
8255 struct nk_color bottom)
8256{
8257 void *vtx;
8258 struct nk_colorf col_left, col_top;
8259 struct nk_colorf col_right, col_bottom;
8260 nk_draw_index *idx;
8261 nk_draw_index index;
8262
8263 nk_color_fv(&col_left.r, left);
8264 nk_color_fv(&col_right.r, right);
8265 nk_color_fv(&col_top.r, top);
8266 nk_color_fv(&col_bottom.r, bottom);
8267
8268 NK_ASSERT(list);
8269 if (!list) return;
8270
8271 nk_draw_list_push_image(list, list->config.null.texture);
8272 index = (nk_draw_index)list->vertex_count;
8273 vtx = nk_draw_list_alloc_vertices(list, 4);
8274 idx = nk_draw_list_alloc_elements(list, 6);
8275 if (!vtx || !idx) return;
8276
8277 idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);
8278 idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);
8279 idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);
8280
8281 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.null.uv, col_left);
8282 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.null.uv, col_top);
8283 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.null.uv, col_right);
8284 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.null.uv, col_bottom);
8285}
8286
8287NK_API void
8288nk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a,
8289 struct nk_vec2 b, struct nk_vec2 c, struct nk_color col)
8290{
8291 NK_ASSERT(list);
8292 if (!list || !col.a) return;
8293 nk_draw_list_path_line_to(list, a);
8294 nk_draw_list_path_line_to(list, b);
8295 nk_draw_list_path_line_to(list, c);
8296 nk_draw_list_path_fill(list, col);
8297}
8298
8299NK_API void
8300nk_draw_list_stroke_triangle(struct nk_draw_list *list, struct nk_vec2 a,
8301 struct nk_vec2 b, struct nk_vec2 c, struct nk_color col, float thickness)
8302{
8303 NK_ASSERT(list);
8304 if (!list || !col.a) return;
8305 nk_draw_list_path_line_to(list, a);
8306 nk_draw_list_path_line_to(list, b);
8307 nk_draw_list_path_line_to(list, c);
8308 nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);
8309}
8310
8311NK_API void
8312nk_draw_list_fill_circle(struct nk_draw_list *list, struct nk_vec2 center,
8313 float radius, struct nk_color col, unsigned int segs)
8314{
8315 float a_max;
8316 NK_ASSERT(list);
8317 if (!list || !col.a) return;
8318 a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;
8319 nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);
8320 nk_draw_list_path_fill(list, col);
8321}
8322
8323NK_API void
8324nk_draw_list_stroke_circle(struct nk_draw_list *list, struct nk_vec2 center,
8325 float radius, struct nk_color col, unsigned int segs, float thickness)
8326{
8327 float a_max;
8328 NK_ASSERT(list);
8329 if (!list || !col.a) return;
8330 a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;
8331 nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);
8332 nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);
8333}
8334
8335NK_API void
8336nk_draw_list_stroke_curve(struct nk_draw_list *list, struct nk_vec2 p0,
8337 struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1,
8338 struct nk_color col, unsigned int segments, float thickness)
8339{
8340 NK_ASSERT(list);
8341 if (!list || !col.a) return;
8342 nk_draw_list_path_line_to(list, p0);
8343 nk_draw_list_path_curve_to(list, cp0, cp1, p1, segments);
8344 nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness);
8345}
8346
8347NK_INTERN void
8348nk_draw_list_push_rect_uv(struct nk_draw_list *list, struct nk_vec2 a,
8349 struct nk_vec2 c, struct nk_vec2 uva, struct nk_vec2 uvc,
8350 struct nk_color color)
8351{
8352 void *vtx;
8353 struct nk_vec2 uvb;
8354 struct nk_vec2 uvd;
8355 struct nk_vec2 b;
8356 struct nk_vec2 d;
8357
8358 struct nk_colorf col;
8359 nk_draw_index *idx;
8360 nk_draw_index index;
8361 NK_ASSERT(list);
8362 if (!list) return;
8363
8364 nk_color_fv(&col.r, color);
8365 uvb = nk_vec2(uvc.x, uva.y);
8366 uvd = nk_vec2(uva.x, uvc.y);
8367 b = nk_vec2(c.x, a.y);
8368 d = nk_vec2(a.x, c.y);
8369
8370 index = (nk_draw_index)list->vertex_count;
8371 vtx = nk_draw_list_alloc_vertices(list, 4);
8372 idx = nk_draw_list_alloc_elements(list, 6);
8373 if (!vtx || !idx) return;
8374
8375 idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);
8376 idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);
8377 idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);
8378
8379 vtx = nk_draw_vertex(vtx, &list->config, a, uva, col);
8380 vtx = nk_draw_vertex(vtx, &list->config, b, uvb, col);
8381 vtx = nk_draw_vertex(vtx, &list->config, c, uvc, col);
8382 vtx = nk_draw_vertex(vtx, &list->config, d, uvd, col);
8383}
8384
8385NK_API void
8386nk_draw_list_add_image(struct nk_draw_list *list, struct nk_image texture,
8387 struct nk_rect rect, struct nk_color color)
8388{
8389 NK_ASSERT(list);
8390 if (!list) return;
8391 /* push new command with given texture */
8392 nk_draw_list_push_image(list, texture.handle);
8393 if (nk_image_is_subimage(&texture)) {
8394 /* add region inside of the texture */
8395 struct nk_vec2 uv[2];
8396 uv[0].x = (float)texture.region[0]/(float)texture.w;
8397 uv[0].y = (float)texture.region[1]/(float)texture.h;
8398 uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w;
8399 uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h;
8400 nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),
8401 nk_vec2(rect.x + rect.w, rect.y + rect.h), uv[0], uv[1], color);
8402 } else nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),
8403 nk_vec2(rect.x + rect.w, rect.y + rect.h),
8404 nk_vec2(0.0f, 0.0f), nk_vec2(1.0f, 1.0f),color);
8405}
8406
8407NK_API void
8408nk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font,
8409 struct nk_rect rect, const char *text, int len, float font_height,
8410 struct nk_color fg)
8411{
8412 float x = 0;
8413 int text_len = 0;
8414 nk_rune unicode = 0;
8415 nk_rune next = 0;
8416 int glyph_len = 0;
8417 int next_glyph_len = 0;
8418 struct nk_user_font_glyph g;
8419
8420 NK_ASSERT(list);
8421 if (!list || !len || !text) return;
8422 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
8423 list->clip_rect.x, list->clip_rect.y, list->clip_rect.w, list->clip_rect.h)) return;
8424
8425 nk_draw_list_push_image(list, font->texture);
8426 x = rect.x;
8427 glyph_len = nk_utf_decode(text, &unicode, len);
8428 if (!glyph_len) return;
8429
8430 /* draw every glyph image */
8431 fg.a = (nk_byte)((float)fg.a * list->config.global_alpha);
8432 while (text_len < len && glyph_len) {
8433 float gx, gy, gh, gw;
8434 float char_width = 0;
8435 if (unicode == NK_UTF_INVALID) break;
8436
8437 /* query currently drawn glyph information */
8438 next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len);
8439 font->query(font->userdata, font_height, &g, unicode,
8440 (next == NK_UTF_INVALID) ? '\0' : next);
8441
8442 /* calculate and draw glyph drawing rectangle and image */
8443 gx = x + g.offset.x;
8444 gy = rect.y + g.offset.y;
8445 gw = g.width; gh = g.height;
8446 char_width = g.xadvance;
8447 nk_draw_list_push_rect_uv(list, nk_vec2(gx,gy), nk_vec2(gx + gw, gy+ gh),
8448 g.uv[0], g.uv[1], fg);
8449
8450 /* offset next glyph */
8451 text_len += glyph_len;
8452 x += char_width;
8453 glyph_len = next_glyph_len;
8454 unicode = next;
8455 }
8456}
8457
8458NK_API nk_flags
8459nk_convert(struct nk_context *ctx, struct nk_buffer *cmds,
8460 struct nk_buffer *vertices, struct nk_buffer *elements,
8461 const struct nk_convert_config *config)
8462{
8463 nk_flags res = NK_CONVERT_SUCCESS;
8464 const struct nk_command *cmd;
8465 NK_ASSERT(ctx);
8466 NK_ASSERT(cmds);
8467 NK_ASSERT(vertices);
8468 NK_ASSERT(elements);
8469 NK_ASSERT(config);
8470 NK_ASSERT(config->vertex_layout);
8471 NK_ASSERT(config->vertex_size);
8472 if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout)
8473 return NK_CONVERT_INVALID_PARAM;
8474
8475 nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements);
8476 nk_foreach(cmd, ctx)
8477 {
8478#ifdef NK_INCLUDE_COMMAND_USERDATA
8479 ctx->draw_list.userdata = cmd->userdata;
8480#endif
8481 switch (cmd->type) {
8482 case NK_COMMAND_NOP: break;
8483 case NK_COMMAND_SCISSOR: {
8484 const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd;
8485 nk_draw_list_add_clip(&ctx->draw_list, nk_rect(s->x, s->y, s->w, s->h));
8486 } break;
8487 case NK_COMMAND_LINE: {
8488 const struct nk_command_line *l = (const struct nk_command_line*)cmd;
8489 nk_draw_list_stroke_line(&ctx->draw_list, nk_vec2(l->begin.x, l->begin.y),
8490 nk_vec2(l->end.x, l->end.y), l->color, l->line_thickness);
8491 } break;
8492 case NK_COMMAND_CURVE: {
8493 const struct nk_command_curve *q = (const struct nk_command_curve*)cmd;
8494 nk_draw_list_stroke_curve(&ctx->draw_list, nk_vec2(q->begin.x, q->begin.y),
8495 nk_vec2(q->ctrl[0].x, q->ctrl[0].y), nk_vec2(q->ctrl[1].x,
8496 q->ctrl[1].y), nk_vec2(q->end.x, q->end.y), q->color,
8497 config->curve_segment_count, q->line_thickness);
8498 } break;
8499 case NK_COMMAND_RECT: {
8500 const struct nk_command_rect *r = (const struct nk_command_rect*)cmd;
8501 nk_draw_list_stroke_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),
8502 r->color, (float)r->rounding, r->line_thickness);
8503 } break;
8504 case NK_COMMAND_RECT_FILLED: {
8505 const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled*)cmd;
8506 nk_draw_list_fill_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),
8507 r->color, (float)r->rounding);
8508 } break;
8509 case NK_COMMAND_RECT_MULTI_COLOR: {
8510 const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color*)cmd;
8511 nk_draw_list_fill_rect_multi_color(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),
8512 r->left, r->top, r->right, r->bottom);
8513 } break;
8514 case NK_COMMAND_CIRCLE: {
8515 const struct nk_command_circle *c = (const struct nk_command_circle*)cmd;
8516 nk_draw_list_stroke_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,
8517 (float)c->y + (float)c->h/2), (float)c->w/2, c->color,
8518 config->circle_segment_count, c->line_thickness);
8519 } break;
8520 case NK_COMMAND_CIRCLE_FILLED: {
8521 const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
8522 nk_draw_list_fill_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,
8523 (float)c->y + (float)c->h/2), (float)c->w/2, c->color,
8524 config->circle_segment_count);
8525 } break;
8526 case NK_COMMAND_ARC: {
8527 const struct nk_command_arc *c = (const struct nk_command_arc*)cmd;
8528 nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));
8529 nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,
8530 c->a[0], c->a[1], config->arc_segment_count);
8531 nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_CLOSED, c->line_thickness);
8532 } break;
8533 case NK_COMMAND_ARC_FILLED: {
8534 const struct nk_command_arc_filled *c = (const struct nk_command_arc_filled*)cmd;
8535 nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));
8536 nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,
8537 c->a[0], c->a[1], config->arc_segment_count);
8538 nk_draw_list_path_fill(&ctx->draw_list, c->color);
8539 } break;
8540 case NK_COMMAND_TRIANGLE: {
8541 const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd;
8542 nk_draw_list_stroke_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),
8543 nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color,
8544 t->line_thickness);
8545 } break;
8546 case NK_COMMAND_TRIANGLE_FILLED: {
8547 const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd;
8548 nk_draw_list_fill_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),
8549 nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color);
8550 } break;
8551 case NK_COMMAND_POLYGON: {
8552 int i;
8553 const struct nk_command_polygon*p = (const struct nk_command_polygon*)cmd;
8554 for (i = 0; i < p->point_count; ++i) {
8555 struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);
8556 nk_draw_list_path_line_to(&ctx->draw_list, pnt);
8557 }
8558 nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_CLOSED, p->line_thickness);
8559 } break;
8560 case NK_COMMAND_POLYGON_FILLED: {
8561 int i;
8562 const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd;
8563 for (i = 0; i < p->point_count; ++i) {
8564 struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);
8565 nk_draw_list_path_line_to(&ctx->draw_list, pnt);
8566 }
8567 nk_draw_list_path_fill(&ctx->draw_list, p->color);
8568 } break;
8569 case NK_COMMAND_POLYLINE: {
8570 int i;
8571 const struct nk_command_polyline *p = (const struct nk_command_polyline*)cmd;
8572 for (i = 0; i < p->point_count; ++i) {
8573 struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);
8574 nk_draw_list_path_line_to(&ctx->draw_list, pnt);
8575 }
8576 nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_OPEN, p->line_thickness);
8577 } break;
8578 case NK_COMMAND_TEXT: {
8579 const struct nk_command_text *t = (const struct nk_command_text*)cmd;
8580 nk_draw_list_add_text(&ctx->draw_list, t->font, nk_rect(t->x, t->y, t->w, t->h),
8581 t->string, t->length, t->height, t->foreground);
8582 } break;
8583 case NK_COMMAND_IMAGE: {
8584 const struct nk_command_image *i = (const struct nk_command_image*)cmd;
8585 nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col);
8586 } break;
8587 case NK_COMMAND_CUSTOM: {
8588 const struct nk_command_custom *c = (const struct nk_command_custom*)cmd;
8589 c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data);
8590 } break;
8591 default: break;
8592 }
8593 }
8594 res |= (cmds->needed > cmds->allocated) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0;
8595 res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0;
8596 res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0;
8597 return res;
8598}
8599NK_API const struct nk_draw_command*
8600nk__draw_begin(const struct nk_context *ctx,
8601 const struct nk_buffer *buffer)
8602{return nk__draw_list_begin(&ctx->draw_list, buffer);}
8603
8604NK_API const struct nk_draw_command*
8605nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buffer)
8606{return nk__draw_list_end(&ctx->draw_list, buffer);}
8607
8608NK_API const struct nk_draw_command*
8609nk__draw_next(const struct nk_draw_command *cmd,
8610 const struct nk_buffer *buffer, const struct nk_context *ctx)
8611{return nk__draw_list_next(cmd, buffer, &ctx->draw_list);}
8612
8613#endif
8614
8615/*
8616 * ==============================================================
8617 *
8618 * FONT HANDLING
8619 *
8620 * ===============================================================
8621 */
8622#ifdef NK_INCLUDE_FONT_BAKING
8623/* -------------------------------------------------------------
8624 *
8625 * RECT PACK
8626 *
8627 * --------------------------------------------------------------*/
8628/* stb_rect_pack.h - v0.05 - public domain - rectangle packing */
8629/* Sean Barrett 2014 */
8630#define NK_RP__MAXVAL 0xffff
8631typedef unsigned short nk_rp_coord;
8632
8633struct nk_rp_rect {
8634 /* reserved for your use: */
8635 int id;
8636 /* input: */
8637 nk_rp_coord w, h;
8638 /* output: */
8639 nk_rp_coord x, y;
8640 int was_packed;
8641 /* non-zero if valid packing */
8642}; /* 16 bytes, nominally */
8643
8644struct nk_rp_node {
8645 nk_rp_coord x,y;
8646 struct nk_rp_node *next;
8647};
8648
8649struct nk_rp_context {
8650 int width;
8651 int height;
8652 int align;
8653 int init_mode;
8654 int heuristic;
8655 int num_nodes;
8656 struct nk_rp_node *active_head;
8657 struct nk_rp_node *free_head;
8658 struct nk_rp_node extra[2];
8659 /* we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' */
8660};
8661
8662struct nk_rp__findresult {
8663 int x,y;
8664 struct nk_rp_node **prev_link;
8665};
8666
8667enum NK_RP_HEURISTIC {
8668 NK_RP_HEURISTIC_Skyline_default=0,
8669 NK_RP_HEURISTIC_Skyline_BL_sortHeight = NK_RP_HEURISTIC_Skyline_default,
8670 NK_RP_HEURISTIC_Skyline_BF_sortHeight
8671};
8672enum NK_RP_INIT_STATE{NK_RP__INIT_skyline = 1};
8673
8674NK_INTERN void
8675nk_rp_setup_allow_out_of_mem(struct nk_rp_context *context, int allow_out_of_mem)
8676{
8677 if (allow_out_of_mem)
8678 /* if it's ok to run out of memory, then don't bother aligning them; */
8679 /* this gives better packing, but may fail due to OOM (even though */
8680 /* the rectangles easily fit). @TODO a smarter approach would be to only */
8681 /* quantize once we've hit OOM, then we could get rid of this parameter. */
8682 context->align = 1;
8683 else {
8684 /* if it's not ok to run out of memory, then quantize the widths */
8685 /* so that num_nodes is always enough nodes. */
8686 /* */
8687 /* I.e. num_nodes * align >= width */
8688 /* align >= width / num_nodes */
8689 /* align = ceil(width/num_nodes) */
8690 context->align = (context->width + context->num_nodes-1) / context->num_nodes;
8691 }
8692}
8693
8694NK_INTERN void
8695nk_rp_init_target(struct nk_rp_context *context, int width, int height,
8696 struct nk_rp_node *nodes, int num_nodes)
8697{
8698 int i;
8699#ifndef STBRP_LARGE_RECTS
8700 NK_ASSERT(width <= 0xffff && height <= 0xffff);
8701#endif
8702
8703 for (i=0; i < num_nodes-1; ++i)
8704 nodes[i].next = &nodes[i+1];
8705 nodes[i].next = 0;
8706 context->init_mode = NK_RP__INIT_skyline;
8707 context->heuristic = NK_RP_HEURISTIC_Skyline_default;
8708 context->free_head = &nodes[0];
8709 context->active_head = &context->extra[0];
8710 context->width = width;
8711 context->height = height;
8712 context->num_nodes = num_nodes;
8713 nk_rp_setup_allow_out_of_mem(context, 0);
8714
8715 /* node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) */
8716 context->extra[0].x = 0;
8717 context->extra[0].y = 0;
8718 context->extra[0].next = &context->extra[1];
8719 context->extra[1].x = (nk_rp_coord) width;
8720 context->extra[1].y = 65535;
8721 context->extra[1].next = 0;
8722}
8723
8724/* find minimum y position if it starts at x1 */
8725NK_INTERN int
8726nk_rp__skyline_find_min_y(struct nk_rp_context *c, struct nk_rp_node *first,
8727 int x0, int width, int *pwaste)
8728{
8729 struct nk_rp_node *node = first;
8730 int x1 = x0 + width;
8731 int min_y, visited_width, waste_area;
8732 NK_ASSERT(first->x <= x0);
8733 NK_UNUSED(c);
8734
8735 NK_ASSERT(node->next->x > x0);
8736 /* we ended up handling this in the caller for efficiency */
8737 NK_ASSERT(node->x <= x0);
8738
8739 min_y = 0;
8740 waste_area = 0;
8741 visited_width = 0;
8742 while (node->x < x1)
8743 {
8744 if (node->y > min_y) {
8745 /* raise min_y higher. */
8746 /* we've accounted for all waste up to min_y, */
8747 /* but we'll now add more waste for everything we've visited */
8748 waste_area += visited_width * (node->y - min_y);
8749 min_y = node->y;
8750 /* the first time through, visited_width might be reduced */
8751 if (node->x < x0)
8752 visited_width += node->next->x - x0;
8753 else
8754 visited_width += node->next->x - node->x;
8755 } else {
8756 /* add waste area */
8757 int under_width = node->next->x - node->x;
8758 if (under_width + visited_width > width)
8759 under_width = width - visited_width;
8760 waste_area += under_width * (min_y - node->y);
8761 visited_width += under_width;
8762 }
8763 node = node->next;
8764 }
8765 *pwaste = waste_area;
8766 return min_y;
8767}
8768
8769NK_INTERN struct nk_rp__findresult
8770nk_rp__skyline_find_best_pos(struct nk_rp_context *c, int width, int height)
8771{
8772 int best_waste = (1<<30), best_x, best_y = (1 << 30);
8773 struct nk_rp__findresult fr;
8774 struct nk_rp_node **prev, *node, *tail, **best = 0;
8775
8776 /* align to multiple of c->align */
8777 width = (width + c->align - 1);
8778 width -= width % c->align;
8779 NK_ASSERT(width % c->align == 0);
8780
8781 node = c->active_head;
8782 prev = &c->active_head;
8783 while (node->x + width <= c->width) {
8784 int y,waste;
8785 y = nk_rp__skyline_find_min_y(c, node, node->x, width, &waste);
8786 /* actually just want to test BL */
8787 if (c->heuristic == NK_RP_HEURISTIC_Skyline_BL_sortHeight) {
8788 /* bottom left */
8789 if (y < best_y) {
8790 best_y = y;
8791 best = prev;
8792 }
8793 } else {
8794 /* best-fit */
8795 if (y + height <= c->height) {
8796 /* can only use it if it first vertically */
8797 if (y < best_y || (y == best_y && waste < best_waste)) {
8798 best_y = y;
8799 best_waste = waste;
8800 best = prev;
8801 }
8802 }
8803 }
8804 prev = &node->next;
8805 node = node->next;
8806 }
8807 best_x = (best == 0) ? 0 : (*best)->x;
8808
8809 /* if doing best-fit (BF), we also have to try aligning right edge to each node position */
8810 /* */
8811 /* e.g, if fitting */
8812 /* */
8813 /* ____________________ */
8814 /* |____________________| */
8815 /* */
8816 /* into */
8817 /* */
8818 /* | | */
8819 /* | ____________| */
8820 /* |____________| */
8821 /* */
8822 /* then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned */
8823 /* */
8824 /* This makes BF take about 2x the time */
8825 if (c->heuristic == NK_RP_HEURISTIC_Skyline_BF_sortHeight)
8826 {
8827 tail = c->active_head;
8828 node = c->active_head;
8829 prev = &c->active_head;
8830 /* find first node that's admissible */
8831 while (tail->x < width)
8832 tail = tail->next;
8833 while (tail)
8834 {
8835 int xpos = tail->x - width;
8836 int y,waste;
8837 NK_ASSERT(xpos >= 0);
8838 /* find the left position that matches this */
8839 while (node->next->x <= xpos) {
8840 prev = &node->next;
8841 node = node->next;
8842 }
8843 NK_ASSERT(node->next->x > xpos && node->x <= xpos);
8844 y = nk_rp__skyline_find_min_y(c, node, xpos, width, &waste);
8845 if (y + height < c->height) {
8846 if (y <= best_y) {
8847 if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
8848 best_x = xpos;
8849 NK_ASSERT(y <= best_y);
8850 best_y = y;
8851 best_waste = waste;
8852 best = prev;
8853 }
8854 }
8855 }
8856 tail = tail->next;
8857 }
8858 }
8859 fr.prev_link = best;
8860 fr.x = best_x;
8861 fr.y = best_y;
8862 return fr;
8863}
8864
8865NK_INTERN struct nk_rp__findresult
8866nk_rp__skyline_pack_rectangle(struct nk_rp_context *context, int width, int height)
8867{
8868 /* find best position according to heuristic */
8869 struct nk_rp__findresult res = nk_rp__skyline_find_best_pos(context, width, height);
8870 struct nk_rp_node *node, *cur;
8871
8872 /* bail if: */
8873 /* 1. it failed */
8874 /* 2. the best node doesn't fit (we don't always check this) */
8875 /* 3. we're out of memory */
8876 if (res.prev_link == 0 || res.y + height > context->height || context->free_head == 0) {
8877 res.prev_link = 0;
8878 return res;
8879 }
8880
8881 /* on success, create new node */
8882 node = context->free_head;
8883 node->x = (nk_rp_coord) res.x;
8884 node->y = (nk_rp_coord) (res.y + height);
8885
8886 context->free_head = node->next;
8887
8888 /* insert the new node into the right starting point, and */
8889 /* let 'cur' point to the remaining nodes needing to be */
8890 /* stitched back in */
8891 cur = *res.prev_link;
8892 if (cur->x < res.x) {
8893 /* preserve the existing one, so start testing with the next one */
8894 struct nk_rp_node *next = cur->next;
8895 cur->next = node;
8896 cur = next;
8897 } else {
8898 *res.prev_link = node;
8899 }
8900
8901 /* from here, traverse cur and free the nodes, until we get to one */
8902 /* that shouldn't be freed */
8903 while (cur->next && cur->next->x <= res.x + width) {
8904 struct nk_rp_node *next = cur->next;
8905 /* move the current node to the free list */
8906 cur->next = context->free_head;
8907 context->free_head = cur;
8908 cur = next;
8909 }
8910 /* stitch the list back in */
8911 node->next = cur;
8912
8913 if (cur->x < res.x + width)
8914 cur->x = (nk_rp_coord) (res.x + width);
8915 return res;
8916}
8917
8918NK_INTERN int
8919nk_rect_height_compare(const void *a, const void *b)
8920{
8921 const struct nk_rp_rect *p = (const struct nk_rp_rect *) a;
8922 const struct nk_rp_rect *q = (const struct nk_rp_rect *) b;
8923 if (p->h > q->h)
8924 return -1;
8925 if (p->h < q->h)
8926 return 1;
8927 return (p->w > q->w) ? -1 : (p->w < q->w);
8928}
8929
8930NK_INTERN int
8931nk_rect_original_order(const void *a, const void *b)
8932{
8933 const struct nk_rp_rect *p = (const struct nk_rp_rect *) a;
8934 const struct nk_rp_rect *q = (const struct nk_rp_rect *) b;
8935 return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
8936}
8937
8938static void
8939nk_rp_qsort(struct nk_rp_rect *array, unsigned int len, int(*cmp)(const void*,const void*))
8940{
8941 /* iterative quick sort */
8942 #define NK_MAX_SORT_STACK 64
8943 unsigned right, left = 0, stack[NK_MAX_SORT_STACK], pos = 0;
8944 unsigned seed = len/2 * 69069+1;
8945 for (;;) {
8946 for (; left+1 < len; len++) {
8947 struct nk_rp_rect pivot, tmp;
8948 if (pos == NK_MAX_SORT_STACK) len = stack[pos = 0];
8949 pivot = array[left+seed%(len-left)];
8950 seed = seed * 69069 + 1;
8951 stack[pos++] = len;
8952 for (right = left-1;;) {
8953 while (cmp(&array[++right], &pivot) < 0);
8954 while (cmp(&pivot, &array[--len]) < 0);
8955 if (right >= len) break;
8956 tmp = array[right];
8957 array[right] = array[len];
8958 array[len] = tmp;
8959 }
8960 }
8961 if (pos == 0) break;
8962 left = len;
8963 len = stack[--pos];
8964 }
8965 #undef NK_MAX_SORT_STACK
8966}
8967
8968NK_INTERN void
8969nk_rp_pack_rects(struct nk_rp_context *context, struct nk_rp_rect *rects, int num_rects)
8970{
8971 int i;
8972 /* we use the 'was_packed' field internally to allow sorting/unsorting */
8973 for (i=0; i < num_rects; ++i) {
8974 rects[i].was_packed = i;
8975 }
8976
8977 /* sort according to heuristic */
8978 nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_height_compare);
8979
8980 for (i=0; i < num_rects; ++i) {
8981 struct nk_rp__findresult fr = nk_rp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
8982 if (fr.prev_link) {
8983 rects[i].x = (nk_rp_coord) fr.x;
8984 rects[i].y = (nk_rp_coord) fr.y;
8985 } else {
8986 rects[i].x = rects[i].y = NK_RP__MAXVAL;
8987 }
8988 }
8989
8990 /* unsort */
8991 nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_original_order);
8992
8993 /* set was_packed flags */
8994 for (i=0; i < num_rects; ++i)
8995 rects[i].was_packed = !(rects[i].x == NK_RP__MAXVAL && rects[i].y == NK_RP__MAXVAL);
8996}
8997
8998/*
8999 * ==============================================================
9000 *
9001 * TRUETYPE
9002 *
9003 * ===============================================================
9004 */
9005/* stb_truetype.h - v1.07 - public domain */
9006#define NK_TT_MAX_OVERSAMPLE 8
9007#define NK_TT__OVER_MASK (NK_TT_MAX_OVERSAMPLE-1)
9008
9009struct nk_tt_bakedchar {
9010 unsigned short x0,y0,x1,y1;
9011 /* coordinates of bbox in bitmap */
9012 float xoff,yoff,xadvance;
9013};
9014
9015struct nk_tt_aligned_quad{
9016 float x0,y0,s0,t0; /* top-left */
9017 float x1,y1,s1,t1; /* bottom-right */
9018};
9019
9020struct nk_tt_packedchar {
9021 unsigned short x0,y0,x1,y1;
9022 /* coordinates of bbox in bitmap */
9023 float xoff,yoff,xadvance;
9024 float xoff2,yoff2;
9025};
9026
9027struct nk_tt_pack_range {
9028 float font_size;
9029 int first_unicode_codepoint_in_range;
9030 /* if non-zero, then the chars are continuous, and this is the first codepoint */
9031 int *array_of_unicode_codepoints;
9032 /* if non-zero, then this is an array of unicode codepoints */
9033 int num_chars;
9034 struct nk_tt_packedchar *chardata_for_range; /* output */
9035 unsigned char h_oversample, v_oversample;
9036 /* don't set these, they're used internally */
9037};
9038
9039struct nk_tt_pack_context {
9040 void *pack_info;
9041 int width;
9042 int height;
9043 int stride_in_bytes;
9044 int padding;
9045 unsigned int h_oversample, v_oversample;
9046 unsigned char *pixels;
9047 void *nodes;
9048};
9049
9050struct nk_tt_fontinfo {
9051 const unsigned char* data; /* pointer to .ttf file */
9052 int fontstart;/* offset of start of font */
9053 int numGlyphs;/* number of glyphs, needed for range checking */
9054 int loca,head,glyf,hhea,hmtx,kern; /* table locations as offset from start of .ttf */
9055 int index_map; /* a cmap mapping for our chosen character encoding */
9056 int indexToLocFormat; /* format needed to map from glyph index to glyph */
9057};
9058
9059enum {
9060 NK_TT_vmove=1,
9061 NK_TT_vline,
9062 NK_TT_vcurve
9063};
9064
9065struct nk_tt_vertex {
9066 short x,y,cx,cy;
9067 unsigned char type,padding;
9068};
9069
9070struct nk_tt__bitmap{
9071 int w,h,stride;
9072 unsigned char *pixels;
9073};
9074
9075struct nk_tt__hheap_chunk {
9076 struct nk_tt__hheap_chunk *next;
9077};
9078struct nk_tt__hheap {
9079 struct nk_allocator alloc;
9080 struct nk_tt__hheap_chunk *head;
9081 void *first_free;
9082 int num_remaining_in_head_chunk;
9083};
9084
9085struct nk_tt__edge {
9086 float x0,y0, x1,y1;
9087 int invert;
9088};
9089
9090struct nk_tt__active_edge {
9091 struct nk_tt__active_edge *next;
9092 float fx,fdx,fdy;
9093 float direction;
9094 float sy;
9095 float ey;
9096};
9097struct nk_tt__point {float x,y;};
9098
9099#define NK_TT_MACSTYLE_DONTCARE 0
9100#define NK_TT_MACSTYLE_BOLD 1
9101#define NK_TT_MACSTYLE_ITALIC 2
9102#define NK_TT_MACSTYLE_UNDERSCORE 4
9103#define NK_TT_MACSTYLE_NONE 8
9104/* <= not same as 0, this makes us check the bitfield is 0 */
9105
9106enum { /* platformID */
9107 NK_TT_PLATFORM_ID_UNICODE =0,
9108 NK_TT_PLATFORM_ID_MAC =1,
9109 NK_TT_PLATFORM_ID_ISO =2,
9110 NK_TT_PLATFORM_ID_MICROSOFT =3
9111};
9112
9113enum { /* encodingID for NK_TT_PLATFORM_ID_UNICODE */
9114 NK_TT_UNICODE_EID_UNICODE_1_0 =0,
9115 NK_TT_UNICODE_EID_UNICODE_1_1 =1,
9116 NK_TT_UNICODE_EID_ISO_10646 =2,
9117 NK_TT_UNICODE_EID_UNICODE_2_0_BMP=3,
9118 NK_TT_UNICODE_EID_UNICODE_2_0_FULL=4
9119};
9120
9121enum { /* encodingID for NK_TT_PLATFORM_ID_MICROSOFT */
9122 NK_TT_MS_EID_SYMBOL =0,
9123 NK_TT_MS_EID_UNICODE_BMP =1,
9124 NK_TT_MS_EID_SHIFTJIS =2,
9125 NK_TT_MS_EID_UNICODE_FULL =10
9126};
9127
9128enum { /* encodingID for NK_TT_PLATFORM_ID_MAC; same as Script Manager codes */
9129 NK_TT_MAC_EID_ROMAN =0, NK_TT_MAC_EID_ARABIC =4,
9130 NK_TT_MAC_EID_JAPANESE =1, NK_TT_MAC_EID_HEBREW =5,
9131 NK_TT_MAC_EID_CHINESE_TRAD =2, NK_TT_MAC_EID_GREEK =6,
9132 NK_TT_MAC_EID_KOREAN =3, NK_TT_MAC_EID_RUSSIAN =7
9133};
9134
9135enum { /* languageID for NK_TT_PLATFORM_ID_MICROSOFT; same as LCID... */
9136 /* problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs */
9137 NK_TT_MS_LANG_ENGLISH =0x0409, NK_TT_MS_LANG_ITALIAN =0x0410,
9138 NK_TT_MS_LANG_CHINESE =0x0804, NK_TT_MS_LANG_JAPANESE =0x0411,
9139 NK_TT_MS_LANG_DUTCH =0x0413, NK_TT_MS_LANG_KOREAN =0x0412,
9140 NK_TT_MS_LANG_FRENCH =0x040c, NK_TT_MS_LANG_RUSSIAN =0x0419,
9141 NK_TT_MS_LANG_GERMAN =0x0407, NK_TT_MS_LANG_SPANISH =0x0409,
9142 NK_TT_MS_LANG_HEBREW =0x040d, NK_TT_MS_LANG_SWEDISH =0x041D
9143};
9144
9145enum { /* languageID for NK_TT_PLATFORM_ID_MAC */
9146 NK_TT_MAC_LANG_ENGLISH =0 , NK_TT_MAC_LANG_JAPANESE =11,
9147 NK_TT_MAC_LANG_ARABIC =12, NK_TT_MAC_LANG_KOREAN =23,
9148 NK_TT_MAC_LANG_DUTCH =4 , NK_TT_MAC_LANG_RUSSIAN =32,
9149 NK_TT_MAC_LANG_FRENCH =1 , NK_TT_MAC_LANG_SPANISH =6 ,
9150 NK_TT_MAC_LANG_GERMAN =2 , NK_TT_MAC_LANG_SWEDISH =5 ,
9151 NK_TT_MAC_LANG_HEBREW =10, NK_TT_MAC_LANG_CHINESE_SIMPLIFIED =33,
9152 NK_TT_MAC_LANG_ITALIAN =3 , NK_TT_MAC_LANG_CHINESE_TRAD =19
9153};
9154
9155#define nk_ttBYTE(p) (* (const nk_byte *) (p))
9156#define nk_ttCHAR(p) (* (const char *) (p))
9157
9158#if defined(NK_BIGENDIAN) && !defined(NK_ALLOW_UNALIGNED_TRUETYPE)
9159 #define nk_ttUSHORT(p) (* (nk_ushort *) (p))
9160 #define nk_ttSHORT(p) (* (nk_short *) (p))
9161 #define nk_ttULONG(p) (* (nk_uint *) (p))
9162 #define nk_ttLONG(p) (* (nk_int *) (p))
9163#else
9164 static nk_ushort nk_ttUSHORT(const nk_byte *p) { return (nk_ushort)(p[0]*256 + p[1]); }
9165 static nk_short nk_ttSHORT(const nk_byte *p) { return (nk_short)(p[0]*256 + p[1]); }
9166 static nk_uint nk_ttULONG(const nk_byte *p) { return (nk_uint)((p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]); }
9167#endif
9168
9169#define nk_tt_tag4(p,c0,c1,c2,c3)\
9170 ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
9171#define nk_tt_tag(p,str) nk_tt_tag4(p,str[0],str[1],str[2],str[3])
9172
9173NK_INTERN int nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc,
9174 int glyph_index, struct nk_tt_vertex **pvertices);
9175
9176NK_INTERN nk_uint
9177nk_tt__find_table(const nk_byte *data, nk_uint fontstart, const char *tag)
9178{
9179 /* @OPTIMIZE: binary search */
9180 nk_int num_tables = nk_ttUSHORT(data+fontstart+4);
9181 nk_uint tabledir = fontstart + 12;
9182 nk_int i;
9183 for (i = 0; i < num_tables; ++i) {
9184 nk_uint loc = tabledir + (nk_uint)(16*i);
9185 if (nk_tt_tag(data+loc+0, tag))
9186 return nk_ttULONG(data+loc+8);
9187 }
9188 return 0;
9189}
9190
9191NK_INTERN int
9192nk_tt_InitFont(struct nk_tt_fontinfo *info, const unsigned char *data2, int fontstart)
9193{
9194 nk_uint cmap, t;
9195 nk_int i,numTables;
9196 const nk_byte *data = (const nk_byte *) data2;
9197
9198 info->data = data;
9199 info->fontstart = fontstart;
9200
9201 cmap = nk_tt__find_table(data, (nk_uint)fontstart, "cmap"); /* required */
9202 info->loca = (int)nk_tt__find_table(data, (nk_uint)fontstart, "loca"); /* required */
9203 info->head = (int)nk_tt__find_table(data, (nk_uint)fontstart, "head"); /* required */
9204 info->glyf = (int)nk_tt__find_table(data, (nk_uint)fontstart, "glyf"); /* required */
9205 info->hhea = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hhea"); /* required */
9206 info->hmtx = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hmtx"); /* required */
9207 info->kern = (int)nk_tt__find_table(data, (nk_uint)fontstart, "kern"); /* not required */
9208 if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)
9209 return 0;
9210
9211 t = nk_tt__find_table(data, (nk_uint)fontstart, "maxp");
9212 if (t) info->numGlyphs = nk_ttUSHORT(data+t+4);
9213 else info->numGlyphs = 0xffff;
9214
9215 /* find a cmap encoding table we understand *now* to avoid searching */
9216 /* later. (todo: could make this installable) */
9217 /* the same regardless of glyph. */
9218 numTables = nk_ttUSHORT(data + cmap + 2);
9219 info->index_map = 0;
9220 for (i=0; i < numTables; ++i)
9221 {
9222 nk_uint encoding_record = cmap + 4 + 8 * (nk_uint)i;
9223 /* find an encoding we understand: */
9224 switch(nk_ttUSHORT(data+encoding_record)) {
9225 case NK_TT_PLATFORM_ID_MICROSOFT:
9226 switch (nk_ttUSHORT(data+encoding_record+2)) {
9227 case NK_TT_MS_EID_UNICODE_BMP:
9228 case NK_TT_MS_EID_UNICODE_FULL:
9229 /* MS/Unicode */
9230 info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4));
9231 break;
9232 default: break;
9233 } break;
9234 case NK_TT_PLATFORM_ID_UNICODE:
9235 /* Mac/iOS has these */
9236 /* all the encodingIDs are unicode, so we don't bother to check it */
9237 info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4));
9238 break;
9239 default: break;
9240 }
9241 }
9242 if (info->index_map == 0)
9243 return 0;
9244 info->indexToLocFormat = nk_ttUSHORT(data+info->head + 50);
9245 return 1;
9246}
9247
9248NK_INTERN int
9249nk_tt_FindGlyphIndex(const struct nk_tt_fontinfo *info, int unicode_codepoint)
9250{
9251 const nk_byte *data = info->data;
9252 nk_uint index_map = (nk_uint)info->index_map;
9253
9254 nk_ushort format = nk_ttUSHORT(data + index_map + 0);
9255 if (format == 0) { /* apple byte encoding */
9256 nk_int bytes = nk_ttUSHORT(data + index_map + 2);
9257 if (unicode_codepoint < bytes-6)
9258 return nk_ttBYTE(data + index_map + 6 + unicode_codepoint);
9259 return 0;
9260 } else if (format == 6) {
9261 nk_uint first = nk_ttUSHORT(data + index_map + 6);
9262 nk_uint count = nk_ttUSHORT(data + index_map + 8);
9263 if ((nk_uint) unicode_codepoint >= first && (nk_uint) unicode_codepoint < first+count)
9264 return nk_ttUSHORT(data + index_map + 10 + (unicode_codepoint - (int)first)*2);
9265 return 0;
9266 } else if (format == 2) {
9267 NK_ASSERT(0); /* @TODO: high-byte mapping for japanese/chinese/korean */
9268 return 0;
9269 } else if (format == 4) { /* standard mapping for windows fonts: binary search collection of ranges */
9270 nk_ushort segcount = nk_ttUSHORT(data+index_map+6) >> 1;
9271 nk_ushort searchRange = nk_ttUSHORT(data+index_map+8) >> 1;
9272 nk_ushort entrySelector = nk_ttUSHORT(data+index_map+10);
9273 nk_ushort rangeShift = nk_ttUSHORT(data+index_map+12) >> 1;
9274
9275 /* do a binary search of the segments */
9276 nk_uint endCount = index_map + 14;
9277 nk_uint search = endCount;
9278
9279 if (unicode_codepoint > 0xffff)
9280 return 0;
9281
9282 /* they lie from endCount .. endCount + segCount */
9283 /* but searchRange is the nearest power of two, so... */
9284 if (unicode_codepoint >= nk_ttUSHORT(data + search + rangeShift*2))
9285 search += (nk_uint)(rangeShift*2);
9286
9287 /* now decrement to bias correctly to find smallest */
9288 search -= 2;
9289 while (entrySelector) {
9290 nk_ushort end;
9291 searchRange >>= 1;
9292 end = nk_ttUSHORT(data + search + searchRange*2);
9293 if (unicode_codepoint > end)
9294 search += (nk_uint)(searchRange*2);
9295 --entrySelector;
9296 }
9297 search += 2;
9298
9299 {
9300 nk_ushort offset, start;
9301 nk_ushort item = (nk_ushort) ((search - endCount) >> 1);
9302
9303 NK_ASSERT(unicode_codepoint <= nk_ttUSHORT(data + endCount + 2*item));
9304 start = nk_ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
9305 if (unicode_codepoint < start)
9306 return 0;
9307
9308 offset = nk_ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
9309 if (offset == 0)
9310 return (nk_ushort) (unicode_codepoint + nk_ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
9311
9312 return nk_ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
9313 }
9314 } else if (format == 12 || format == 13) {
9315 nk_uint ngroups = nk_ttULONG(data+index_map+12);
9316 nk_int low,high;
9317 low = 0; high = (nk_int)ngroups;
9318 /* Binary search the right group. */
9319 while (low < high) {
9320 nk_int mid = low + ((high-low) >> 1); /* rounds down, so low <= mid < high */
9321 nk_uint start_char = nk_ttULONG(data+index_map+16+mid*12);
9322 nk_uint end_char = nk_ttULONG(data+index_map+16+mid*12+4);
9323 if ((nk_uint) unicode_codepoint < start_char)
9324 high = mid;
9325 else if ((nk_uint) unicode_codepoint > end_char)
9326 low = mid+1;
9327 else {
9328 nk_uint start_glyph = nk_ttULONG(data+index_map+16+mid*12+8);
9329 if (format == 12)
9330 return (int)start_glyph + (int)unicode_codepoint - (int)start_char;
9331 else /* format == 13 */
9332 return (int)start_glyph;
9333 }
9334 }
9335 return 0; /* not found */
9336 }
9337 /* @TODO */
9338 NK_ASSERT(0);
9339 return 0;
9340}
9341
9342NK_INTERN void
9343nk_tt_setvertex(struct nk_tt_vertex *v, nk_byte type, nk_int x, nk_int y, nk_int cx, nk_int cy)
9344{
9345 v->type = type;
9346 v->x = (nk_short) x;
9347 v->y = (nk_short) y;
9348 v->cx = (nk_short) cx;
9349 v->cy = (nk_short) cy;
9350}
9351
9352NK_INTERN int
9353nk_tt__GetGlyfOffset(const struct nk_tt_fontinfo *info, int glyph_index)
9354{
9355 int g1,g2;
9356 if (glyph_index >= info->numGlyphs) return -1; /* glyph index out of range */
9357 if (info->indexToLocFormat >= 2) return -1; /* unknown index->glyph map format */
9358
9359 if (info->indexToLocFormat == 0) {
9360 g1 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;
9361 g2 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;
9362 } else {
9363 g1 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4);
9364 g2 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4 + 4);
9365 }
9366 return g1==g2 ? -1 : g1; /* if length is 0, return -1 */
9367}
9368
9369NK_INTERN int
9370nk_tt_GetGlyphBox(const struct nk_tt_fontinfo *info, int glyph_index,
9371 int *x0, int *y0, int *x1, int *y1)
9372{
9373 int g = nk_tt__GetGlyfOffset(info, glyph_index);
9374 if (g < 0) return 0;
9375
9376 if (x0) *x0 = nk_ttSHORT(info->data + g + 2);
9377 if (y0) *y0 = nk_ttSHORT(info->data + g + 4);
9378 if (x1) *x1 = nk_ttSHORT(info->data + g + 6);
9379 if (y1) *y1 = nk_ttSHORT(info->data + g + 8);
9380 return 1;
9381}
9382
9383NK_INTERN int
9384stbtt__close_shape(struct nk_tt_vertex *vertices, int num_vertices, int was_off,
9385 int start_off, nk_int sx, nk_int sy, nk_int scx, nk_int scy, nk_int cx, nk_int cy)
9386{
9387 if (start_off) {
9388 if (was_off)
9389 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
9390 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, sx,sy,scx,scy);
9391 } else {
9392 if (was_off)
9393 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve,sx,sy,cx,cy);
9394 else
9395 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline,sx,sy,0,0);
9396 }
9397 return num_vertices;
9398}
9399
9400NK_INTERN int
9401nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc,
9402 int glyph_index, struct nk_tt_vertex **pvertices)
9403{
9404 nk_short numberOfContours;
9405 const nk_byte *endPtsOfContours;
9406 const nk_byte *data = info->data;
9407 struct nk_tt_vertex *vertices=0;
9408 int num_vertices=0;
9409 int g = nk_tt__GetGlyfOffset(info, glyph_index);
9410 *pvertices = 0;
9411
9412 if (g < 0) return 0;
9413 numberOfContours = nk_ttSHORT(data + g);
9414 if (numberOfContours > 0) {
9415 nk_byte flags=0,flagcount;
9416 nk_int ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
9417 nk_int x,y,cx,cy,sx,sy, scx,scy;
9418 const nk_byte *points;
9419 endPtsOfContours = (data + g + 10);
9420 ins = nk_ttUSHORT(data + g + 10 + numberOfContours * 2);
9421 points = data + g + 10 + numberOfContours * 2 + 2 + ins;
9422
9423 n = 1+nk_ttUSHORT(endPtsOfContours + numberOfContours*2-2);
9424 m = n + 2*numberOfContours; /* a loose bound on how many vertices we might need */
9425 vertices = (struct nk_tt_vertex *)alloc->alloc(alloc->userdata, 0, (nk_size)m * sizeof(vertices[0]));
9426 if (vertices == 0)
9427 return 0;
9428
9429 next_move = 0;
9430 flagcount=0;
9431
9432 /* in first pass, we load uninterpreted data into the allocated array */
9433 /* above, shifted to the end of the array so we won't overwrite it when */
9434 /* we create our final data starting from the front */
9435 off = m - n; /* starting offset for uninterpreted data, regardless of how m ends up being calculated */
9436
9437 /* first load flags */
9438 for (i=0; i < n; ++i) {
9439 if (flagcount == 0) {
9440 flags = *points++;
9441 if (flags & 8)
9442 flagcount = *points++;
9443 } else --flagcount;
9444 vertices[off+i].type = flags;
9445 }
9446
9447 /* now load x coordinates */
9448 x=0;
9449 for (i=0; i < n; ++i) {
9450 flags = vertices[off+i].type;
9451 if (flags & 2) {
9452 nk_short dx = *points++;
9453 x += (flags & 16) ? dx : -dx; /* ??? */
9454 } else {
9455 if (!(flags & 16)) {
9456 x = x + (nk_short) (points[0]*256 + points[1]);
9457 points += 2;
9458 }
9459 }
9460 vertices[off+i].x = (nk_short) x;
9461 }
9462
9463 /* now load y coordinates */
9464 y=0;
9465 for (i=0; i < n; ++i) {
9466 flags = vertices[off+i].type;
9467 if (flags & 4) {
9468 nk_short dy = *points++;
9469 y += (flags & 32) ? dy : -dy; /* ??? */
9470 } else {
9471 if (!(flags & 32)) {
9472 y = y + (nk_short) (points[0]*256 + points[1]);
9473 points += 2;
9474 }
9475 }
9476 vertices[off+i].y = (nk_short) y;
9477 }
9478
9479 /* now convert them to our format */
9480 num_vertices=0;
9481 sx = sy = cx = cy = scx = scy = 0;
9482 for (i=0; i < n; ++i)
9483 {
9484 flags = vertices[off+i].type;
9485 x = (nk_short) vertices[off+i].x;
9486 y = (nk_short) vertices[off+i].y;
9487
9488 if (next_move == i) {
9489 if (i != 0)
9490 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
9491
9492 /* now start the new one */
9493 start_off = !(flags & 1);
9494 if (start_off) {
9495 /* if we start off with an off-curve point, then when we need to find a point on the curve */
9496 /* where we can start, and we need to save some state for when we wraparound. */
9497 scx = x;
9498 scy = y;
9499 if (!(vertices[off+i+1].type & 1)) {
9500 /* next point is also a curve point, so interpolate an on-point curve */
9501 sx = (x + (nk_int) vertices[off+i+1].x) >> 1;
9502 sy = (y + (nk_int) vertices[off+i+1].y) >> 1;
9503 } else {
9504 /* otherwise just use the next point as our start point */
9505 sx = (nk_int) vertices[off+i+1].x;
9506 sy = (nk_int) vertices[off+i+1].y;
9507 ++i; /* we're using point i+1 as the starting point, so skip it */
9508 }
9509 } else {
9510 sx = x;
9511 sy = y;
9512 }
9513 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vmove,sx,sy,0,0);
9514 was_off = 0;
9515 next_move = 1 + nk_ttUSHORT(endPtsOfContours+j*2);
9516 ++j;
9517 } else {
9518 if (!(flags & 1))
9519 { /* if it's a curve */
9520 if (was_off) /* two off-curve control points in a row means interpolate an on-curve midpoint */
9521 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
9522 cx = x;
9523 cy = y;
9524 was_off = 1;
9525 } else {
9526 if (was_off)
9527 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, x,y, cx, cy);
9528 else nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline, x,y,0,0);
9529 was_off = 0;
9530 }
9531 }
9532 }
9533 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
9534 } else if (numberOfContours == -1) {
9535 /* Compound shapes. */
9536 int more = 1;
9537 const nk_byte *comp = data + g + 10;
9538 num_vertices = 0;
9539 vertices = 0;
9540
9541 while (more)
9542 {
9543 nk_ushort flags, gidx;
9544 int comp_num_verts = 0, i;
9545 struct nk_tt_vertex *comp_verts = 0, *tmp = 0;
9546 float mtx[6] = {1,0,0,1,0,0}, m, n;
9547
9548 flags = (nk_ushort)nk_ttSHORT(comp); comp+=2;
9549 gidx = (nk_ushort)nk_ttSHORT(comp); comp+=2;
9550
9551 if (flags & 2) { /* XY values */
9552 if (flags & 1) { /* shorts */
9553 mtx[4] = nk_ttSHORT(comp); comp+=2;
9554 mtx[5] = nk_ttSHORT(comp); comp+=2;
9555 } else {
9556 mtx[4] = nk_ttCHAR(comp); comp+=1;
9557 mtx[5] = nk_ttCHAR(comp); comp+=1;
9558 }
9559 } else {
9560 /* @TODO handle matching point */
9561 NK_ASSERT(0);
9562 }
9563 if (flags & (1<<3)) { /* WE_HAVE_A_SCALE */
9564 mtx[0] = mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2;
9565 mtx[1] = mtx[2] = 0;
9566 } else if (flags & (1<<6)) { /* WE_HAVE_AN_X_AND_YSCALE */
9567 mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2;
9568 mtx[1] = mtx[2] = 0;
9569 mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2;
9570 } else if (flags & (1<<7)) { /* WE_HAVE_A_TWO_BY_TWO */
9571 mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2;
9572 mtx[1] = nk_ttSHORT(comp)/16384.0f; comp+=2;
9573 mtx[2] = nk_ttSHORT(comp)/16384.0f; comp+=2;
9574 mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2;
9575 }
9576
9577 /* Find transformation scales. */
9578 m = (float) NK_SQRT(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
9579 n = (float) NK_SQRT(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
9580
9581 /* Get indexed glyph. */
9582 comp_num_verts = nk_tt_GetGlyphShape(info, alloc, gidx, &comp_verts);
9583 if (comp_num_verts > 0)
9584 {
9585 /* Transform vertices. */
9586 for (i = 0; i < comp_num_verts; ++i) {
9587 struct nk_tt_vertex* v = &comp_verts[i];
9588 short x,y;
9589 x=v->x; y=v->y;
9590 v->x = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
9591 v->y = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
9592 x=v->cx; y=v->cy;
9593 v->cx = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
9594 v->cy = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
9595 }
9596 /* Append vertices. */
9597 tmp = (struct nk_tt_vertex*)alloc->alloc(alloc->userdata, 0,
9598 (nk_size)(num_vertices+comp_num_verts)*sizeof(struct nk_tt_vertex));
9599 if (!tmp) {
9600 if (vertices) alloc->free(alloc->userdata, vertices);
9601 if (comp_verts) alloc->free(alloc->userdata, comp_verts);
9602 return 0;
9603 }
9604 if (num_vertices > 0) NK_MEMCPY(tmp, vertices, (nk_size)num_vertices*sizeof(struct nk_tt_vertex));
9605 NK_MEMCPY(tmp+num_vertices, comp_verts, (nk_size)comp_num_verts*sizeof(struct nk_tt_vertex));
9606 if (vertices) alloc->free(alloc->userdata,vertices);
9607 vertices = tmp;
9608 alloc->free(alloc->userdata,comp_verts);
9609 num_vertices += comp_num_verts;
9610 }
9611 /* More components ? */
9612 more = flags & (1<<5);
9613 }
9614 } else if (numberOfContours < 0) {
9615 /* @TODO other compound variations? */
9616 NK_ASSERT(0);
9617 } else {
9618 /* numberOfCounters == 0, do nothing */
9619 }
9620 *pvertices = vertices;
9621 return num_vertices;
9622}
9623
9624NK_INTERN void
9625nk_tt_GetGlyphHMetrics(const struct nk_tt_fontinfo *info, int glyph_index,
9626 int *advanceWidth, int *leftSideBearing)
9627{
9628 nk_ushort numOfLongHorMetrics = nk_ttUSHORT(info->data+info->hhea + 34);
9629 if (glyph_index < numOfLongHorMetrics) {
9630 if (advanceWidth)
9631 *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index);
9632 if (leftSideBearing)
9633 *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);
9634 } else {
9635 if (advanceWidth)
9636 *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));
9637 if (leftSideBearing)
9638 *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
9639 }
9640}
9641
9642NK_INTERN void
9643nk_tt_GetFontVMetrics(const struct nk_tt_fontinfo *info,
9644 int *ascent, int *descent, int *lineGap)
9645{
9646 if (ascent ) *ascent = nk_ttSHORT(info->data+info->hhea + 4);
9647 if (descent) *descent = nk_ttSHORT(info->data+info->hhea + 6);
9648 if (lineGap) *lineGap = nk_ttSHORT(info->data+info->hhea + 8);
9649}
9650
9651NK_INTERN float
9652nk_tt_ScaleForPixelHeight(const struct nk_tt_fontinfo *info, float height)
9653{
9654 int fheight = nk_ttSHORT(info->data + info->hhea + 4) - nk_ttSHORT(info->data + info->hhea + 6);
9655 return (float) height / (float)fheight;
9656}
9657
9658NK_INTERN float
9659nk_tt_ScaleForMappingEmToPixels(const struct nk_tt_fontinfo *info, float pixels)
9660{
9661 int unitsPerEm = nk_ttUSHORT(info->data + info->head + 18);
9662 return pixels / (float)unitsPerEm;
9663}
9664
9665/*-------------------------------------------------------------
9666 * antialiasing software rasterizer
9667 * --------------------------------------------------------------*/
9668NK_INTERN void
9669nk_tt_GetGlyphBitmapBoxSubpixel(const struct nk_tt_fontinfo *font,
9670 int glyph, float scale_x, float scale_y,float shift_x, float shift_y,
9671 int *ix0, int *iy0, int *ix1, int *iy1)
9672{
9673 int x0,y0,x1,y1;
9674 if (!nk_tt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
9675 /* e.g. space character */
9676 if (ix0) *ix0 = 0;
9677 if (iy0) *iy0 = 0;
9678 if (ix1) *ix1 = 0;
9679 if (iy1) *iy1 = 0;
9680 } else {
9681 /* move to integral bboxes (treating pixels as little squares, what pixels get touched)? */
9682 if (ix0) *ix0 = nk_ifloorf((float)x0 * scale_x + shift_x);
9683 if (iy0) *iy0 = nk_ifloorf((float)-y1 * scale_y + shift_y);
9684 if (ix1) *ix1 = nk_iceilf ((float)x1 * scale_x + shift_x);
9685 if (iy1) *iy1 = nk_iceilf ((float)-y0 * scale_y + shift_y);
9686 }
9687}
9688
9689NK_INTERN void
9690nk_tt_GetGlyphBitmapBox(const struct nk_tt_fontinfo *font, int glyph,
9691 float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
9692{
9693 nk_tt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
9694}
9695
9696/*-------------------------------------------------------------
9697 * Rasterizer
9698 * --------------------------------------------------------------*/
9699NK_INTERN void*
9700nk_tt__hheap_alloc(struct nk_tt__hheap *hh, nk_size size)
9701{
9702 if (hh->first_free) {
9703 void *p = hh->first_free;
9704 hh->first_free = * (void **) p;
9705 return p;
9706 } else {
9707 if (hh->num_remaining_in_head_chunk == 0) {
9708 int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
9709 struct nk_tt__hheap_chunk *c = (struct nk_tt__hheap_chunk *)
9710 hh->alloc.alloc(hh->alloc.userdata, 0,
9711 sizeof(struct nk_tt__hheap_chunk) + size * (nk_size)count);
9712 if (c == 0) return 0;
9713 c->next = hh->head;
9714 hh->head = c;
9715 hh->num_remaining_in_head_chunk = count;
9716 }
9717 --hh->num_remaining_in_head_chunk;
9718 return (char *) (hh->head) + size * (nk_size)hh->num_remaining_in_head_chunk;
9719 }
9720}
9721
9722NK_INTERN void
9723nk_tt__hheap_free(struct nk_tt__hheap *hh, void *p)
9724{
9725 *(void **) p = hh->first_free;
9726 hh->first_free = p;
9727}
9728
9729NK_INTERN void
9730nk_tt__hheap_cleanup(struct nk_tt__hheap *hh)
9731{
9732 struct nk_tt__hheap_chunk *c = hh->head;
9733 while (c) {
9734 struct nk_tt__hheap_chunk *n = c->next;
9735 hh->alloc.free(hh->alloc.userdata, c);
9736 c = n;
9737 }
9738}
9739
9740NK_INTERN struct nk_tt__active_edge*
9741nk_tt__new_active(struct nk_tt__hheap *hh, struct nk_tt__edge *e,
9742 int off_x, float start_point)
9743{
9744 struct nk_tt__active_edge *z = (struct nk_tt__active_edge *)
9745 nk_tt__hheap_alloc(hh, sizeof(*z));
9746 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
9747 /*STBTT_assert(e->y0 <= start_point); */
9748 if (!z) return z;
9749 z->fdx = dxdy;
9750 z->fdy = (dxdy != 0) ? (1/dxdy): 0;
9751 z->fx = e->x0 + dxdy * (start_point - e->y0);
9752 z->fx -= (float)off_x;
9753 z->direction = e->invert ? 1.0f : -1.0f;
9754 z->sy = e->y0;
9755 z->ey = e->y1;
9756 z->next = 0;
9757 return z;
9758}
9759
9760NK_INTERN void
9761nk_tt__handle_clipped_edge(float *scanline, int x, struct nk_tt__active_edge *e,
9762 float x0, float y0, float x1, float y1)
9763{
9764 if (y0 == y1) return;
9765 NK_ASSERT(y0 < y1);
9766 NK_ASSERT(e->sy <= e->ey);
9767 if (y0 > e->ey) return;
9768 if (y1 < e->sy) return;
9769 if (y0 < e->sy) {
9770 x0 += (x1-x0) * (e->sy - y0) / (y1-y0);
9771 y0 = e->sy;
9772 }
9773 if (y1 > e->ey) {
9774 x1 += (x1-x0) * (e->ey - y1) / (y1-y0);
9775 y1 = e->ey;
9776 }
9777
9778 if (x0 == x) NK_ASSERT(x1 <= x+1);
9779 else if (x0 == x+1) NK_ASSERT(x1 >= x);
9780 else if (x0 <= x) NK_ASSERT(x1 <= x);
9781 else if (x0 >= x+1) NK_ASSERT(x1 >= x+1);
9782 else NK_ASSERT(x1 >= x && x1 <= x+1);
9783
9784 if (x0 <= x && x1 <= x)
9785 scanline[x] += e->direction * (y1-y0);
9786 else if (x0 >= x+1 && x1 >= x+1);
9787 else {
9788 NK_ASSERT(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
9789 /* coverage = 1 - average x position */
9790 scanline[x] += (float)e->direction * (float)(y1-y0) * (1.0f-((x0-(float)x)+(x1-(float)x))/2.0f);
9791 }
9792}
9793
9794NK_INTERN void
9795nk_tt__fill_active_edges_new(float *scanline, float *scanline_fill, int len,
9796 struct nk_tt__active_edge *e, float y_top)
9797{
9798 float y_bottom = y_top+1;
9799 while (e)
9800 {
9801 /* brute force every pixel */
9802 /* compute intersection points with top & bottom */
9803 NK_ASSERT(e->ey >= y_top);
9804 if (e->fdx == 0) {
9805 float x0 = e->fx;
9806 if (x0 < len) {
9807 if (x0 >= 0) {
9808 nk_tt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);
9809 nk_tt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);
9810 } else {
9811 nk_tt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
9812 }
9813 }
9814 } else {
9815 float x0 = e->fx;
9816 float dx = e->fdx;
9817 float xb = x0 + dx;
9818 float x_top, x_bottom;
9819 float y0,y1;
9820 float dy = e->fdy;
9821 NK_ASSERT(e->sy <= y_bottom && e->ey >= y_top);
9822
9823 /* compute endpoints of line segment clipped to this scanline (if the */
9824 /* line segment starts on this scanline. x0 is the intersection of the */
9825 /* line with y_top, but that may be off the line segment. */
9826 if (e->sy > y_top) {
9827 x_top = x0 + dx * (e->sy - y_top);
9828 y0 = e->sy;
9829 } else {
9830 x_top = x0;
9831 y0 = y_top;
9832 }
9833
9834 if (e->ey < y_bottom) {
9835 x_bottom = x0 + dx * (e->ey - y_top);
9836 y1 = e->ey;
9837 } else {
9838 x_bottom = xb;
9839 y1 = y_bottom;
9840 }
9841
9842 if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len)
9843 {
9844 /* from here on, we don't have to range check x values */
9845 if ((int) x_top == (int) x_bottom) {
9846 float height;
9847 /* simple case, only spans one pixel */
9848 int x = (int) x_top;
9849 height = y1 - y0;
9850 NK_ASSERT(x >= 0 && x < len);
9851 scanline[x] += e->direction * (1.0f-(((float)x_top - (float)x) + ((float)x_bottom-(float)x))/2.0f) * (float)height;
9852 scanline_fill[x] += e->direction * (float)height; /* everything right of this pixel is filled */
9853 } else {
9854 int x,x1,x2;
9855 float y_crossing, step, sign, area;
9856 /* covers 2+ pixels */
9857 if (x_top > x_bottom)
9858 {
9859 /* flip scanline vertically; signed area is the same */
9860 float t;
9861 y0 = y_bottom - (y0 - y_top);
9862 y1 = y_bottom - (y1 - y_top);
9863 t = y0; y0 = y1; y1 = t;
9864 t = x_bottom; x_bottom = x_top; x_top = t;
9865 dx = -dx;
9866 dy = -dy;
9867 t = x0; x0 = xb; xb = t;
9868 }
9869
9870 x1 = (int) x_top;
9871 x2 = (int) x_bottom;
9872 /* compute intersection with y axis at x1+1 */
9873 y_crossing = ((float)x1+1 - (float)x0) * (float)dy + (float)y_top;
9874
9875 sign = e->direction;
9876 /* area of the rectangle covered from y0..y_crossing */
9877 area = sign * (y_crossing-y0);
9878 /* area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) */
9879 scanline[x1] += area * (1.0f-((float)((float)x_top - (float)x1)+(float)(x1+1-x1))/2.0f);
9880
9881 step = sign * dy;
9882 for (x = x1+1; x < x2; ++x) {
9883 scanline[x] += area + step/2;
9884 area += step;
9885 }
9886 y_crossing += (float)dy * (float)(x2 - (x1+1));
9887
9888 scanline[x2] += area + sign * (1.0f-((float)(x2-x2)+((float)x_bottom-(float)x2))/2.0f) * (y1-y_crossing);
9889 scanline_fill[x2] += sign * (y1-y0);
9890 }
9891 }
9892 else
9893 {
9894 /* if edge goes outside of box we're drawing, we require */
9895 /* clipping logic. since this does not match the intended use */
9896 /* of this library, we use a different, very slow brute */
9897 /* force implementation */
9898 int x;
9899 for (x=0; x < len; ++x)
9900 {
9901 /* cases: */
9902 /* */
9903 /* there can be up to two intersections with the pixel. any intersection */
9904 /* with left or right edges can be handled by splitting into two (or three) */
9905 /* regions. intersections with top & bottom do not necessitate case-wise logic. */
9906 /* */
9907 /* the old way of doing this found the intersections with the left & right edges, */
9908 /* then used some simple logic to produce up to three segments in sorted order */
9909 /* from top-to-bottom. however, this had a problem: if an x edge was epsilon */
9910 /* across the x border, then the corresponding y position might not be distinct */
9911 /* from the other y segment, and it might ignored as an empty segment. to avoid */
9912 /* that, we need to explicitly produce segments based on x positions. */
9913
9914 /* rename variables to clear pairs */
9915 float ya = y_top;
9916 float x1 = (float) (x);
9917 float x2 = (float) (x+1);
9918 float x3 = xb;
9919 float y3 = y_bottom;
9920 float yb,y2;
9921
9922 yb = ((float)x - x0) / dx + y_top;
9923 y2 = ((float)x+1 - x0) / dx + y_top;
9924
9925 if (x0 < x1 && x3 > x2) { /* three segments descending down-right */
9926 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb);
9927 nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x2,y2);
9928 nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
9929 } else if (x3 < x1 && x0 > x2) { /* three segments descending down-left */
9930 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2);
9931 nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x1,yb);
9932 nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3);
9933 } else if (x0 < x1 && x3 > x1) { /* two segments across x, down-right */
9934 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb);
9935 nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3);
9936 } else if (x3 < x1 && x0 > x1) { /* two segments across x, down-left */
9937 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb);
9938 nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3);
9939 } else if (x0 < x2 && x3 > x2) { /* two segments across x+1, down-right */
9940 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2);
9941 nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
9942 } else if (x3 < x2 && x0 > x2) { /* two segments across x+1, down-left */
9943 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2);
9944 nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
9945 } else { /* one segment */
9946 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x3,y3);
9947 }
9948 }
9949 }
9950 }
9951 e = e->next;
9952 }
9953}
9954
9955/* directly AA rasterize edges w/o supersampling */
9956NK_INTERN void
9957nk_tt__rasterize_sorted_edges(struct nk_tt__bitmap *result, struct nk_tt__edge *e,
9958 int n, int vsubsample, int off_x, int off_y, struct nk_allocator *alloc)
9959{
9960 struct nk_tt__hheap hh;
9961 struct nk_tt__active_edge *active = 0;
9962 int y,j=0, i;
9963 float scanline_data[129], *scanline, *scanline2;
9964
9965 NK_UNUSED(vsubsample);
9966 nk_zero_struct(hh);
9967 hh.alloc = *alloc;
9968
9969 if (result->w > 64)
9970 scanline = (float *) alloc->alloc(alloc->userdata,0, (nk_size)(result->w*2+1) * sizeof(float));
9971 else scanline = scanline_data;
9972
9973 scanline2 = scanline + result->w;
9974 y = off_y;
9975 e[n].y0 = (float) (off_y + result->h) + 1;
9976
9977 while (j < result->h)
9978 {
9979 /* find center of pixel for this scanline */
9980 float scan_y_top = (float)y + 0.0f;
9981 float scan_y_bottom = (float)y + 1.0f;
9982 struct nk_tt__active_edge **step = &active;
9983
9984 NK_MEMSET(scanline , 0, (nk_size)result->w*sizeof(scanline[0]));
9985 NK_MEMSET(scanline2, 0, (nk_size)(result->w+1)*sizeof(scanline[0]));
9986
9987 /* update all active edges; */
9988 /* remove all active edges that terminate before the top of this scanline */
9989 while (*step) {
9990 struct nk_tt__active_edge * z = *step;
9991 if (z->ey <= scan_y_top) {
9992 *step = z->next; /* delete from list */
9993 NK_ASSERT(z->direction);
9994 z->direction = 0;
9995 nk_tt__hheap_free(&hh, z);
9996 } else {
9997 step = &((*step)->next); /* advance through list */
9998 }
9999 }
10000
10001 /* insert all edges that start before the bottom of this scanline */
10002 while (e->y0 <= scan_y_bottom) {
10003 if (e->y0 != e->y1) {
10004 struct nk_tt__active_edge *z = nk_tt__new_active(&hh, e, off_x, scan_y_top);
10005 if (z != 0) {
10006 NK_ASSERT(z->ey >= scan_y_top);
10007 /* insert at front */
10008 z->next = active;
10009 active = z;
10010 }
10011 }
10012 ++e;
10013 }
10014
10015 /* now process all active edges */
10016 if (active)
10017 nk_tt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);
10018
10019 {
10020 float sum = 0;
10021 for (i=0; i < result->w; ++i) {
10022 float k;
10023 int m;
10024 sum += scanline2[i];
10025 k = scanline[i] + sum;
10026 k = (float) NK_ABS(k) * 255.0f + 0.5f;
10027 m = (int) k;
10028 if (m > 255) m = 255;
10029 result->pixels[j*result->stride + i] = (unsigned char) m;
10030 }
10031 }
10032 /* advance all the edges */
10033 step = &active;
10034 while (*step) {
10035 struct nk_tt__active_edge *z = *step;
10036 z->fx += z->fdx; /* advance to position for current scanline */
10037 step = &((*step)->next); /* advance through list */
10038 }
10039 ++y;
10040 ++j;
10041 }
10042 nk_tt__hheap_cleanup(&hh);
10043 if (scanline != scanline_data)
10044 alloc->free(alloc->userdata, scanline);
10045}
10046
10047#define NK_TT__COMPARE(a,b) ((a)->y0 < (b)->y0)
10048NK_INTERN void
10049nk_tt__sort_edges_ins_sort(struct nk_tt__edge *p, int n)
10050{
10051 int i,j;
10052 for (i=1; i < n; ++i) {
10053 struct nk_tt__edge t = p[i], *a = &t;
10054 j = i;
10055 while (j > 0) {
10056 struct nk_tt__edge *b = &p[j-1];
10057 int c = NK_TT__COMPARE(a,b);
10058 if (!c) break;
10059 p[j] = p[j-1];
10060 --j;
10061 }
10062 if (i != j)
10063 p[j] = t;
10064 }
10065}
10066
10067NK_INTERN void
10068nk_tt__sort_edges_quicksort(struct nk_tt__edge *p, int n)
10069{
10070 /* threshold for transitioning to insertion sort */
10071 while (n > 12) {
10072 struct nk_tt__edge t;
10073 int c01,c12,c,m,i,j;
10074
10075 /* compute median of three */
10076 m = n >> 1;
10077 c01 = NK_TT__COMPARE(&p[0],&p[m]);
10078 c12 = NK_TT__COMPARE(&p[m],&p[n-1]);
10079
10080 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
10081 if (c01 != c12) {
10082 /* otherwise, we'll need to swap something else to middle */
10083 int z;
10084 c = NK_TT__COMPARE(&p[0],&p[n-1]);
10085 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */
10086 /* 0<mid && mid>n: 0>n => 0; 0<n => n */
10087 z = (c == c12) ? 0 : n-1;
10088 t = p[z];
10089 p[z] = p[m];
10090 p[m] = t;
10091 }
10092
10093 /* now p[m] is the median-of-three */
10094 /* swap it to the beginning so it won't move around */
10095 t = p[0];
10096 p[0] = p[m];
10097 p[m] = t;
10098
10099 /* partition loop */
10100 i=1;
10101 j=n-1;
10102 for(;;) {
10103 /* handling of equality is crucial here */
10104 /* for sentinels & efficiency with duplicates */
10105 for (;;++i) {
10106 if (!NK_TT__COMPARE(&p[i], &p[0])) break;
10107 }
10108 for (;;--j) {
10109 if (!NK_TT__COMPARE(&p[0], &p[j])) break;
10110 }
10111
10112 /* make sure we haven't crossed */
10113 if (i >= j) break;
10114 t = p[i];
10115 p[i] = p[j];
10116 p[j] = t;
10117
10118 ++i;
10119 --j;
10120
10121 }
10122
10123 /* recurse on smaller side, iterate on larger */
10124 if (j < (n-i)) {
10125 nk_tt__sort_edges_quicksort(p,j);
10126 p = p+i;
10127 n = n-i;
10128 } else {
10129 nk_tt__sort_edges_quicksort(p+i, n-i);
10130 n = j;
10131 }
10132 }
10133}
10134
10135NK_INTERN void
10136nk_tt__sort_edges(struct nk_tt__edge *p, int n)
10137{
10138 nk_tt__sort_edges_quicksort(p, n);
10139 nk_tt__sort_edges_ins_sort(p, n);
10140}
10141
10142NK_INTERN void
10143nk_tt__rasterize(struct nk_tt__bitmap *result, struct nk_tt__point *pts,
10144 int *wcount, int windings, float scale_x, float scale_y,
10145 float shift_x, float shift_y, int off_x, int off_y, int invert,
10146 struct nk_allocator *alloc)
10147{
10148 float y_scale_inv = invert ? -scale_y : scale_y;
10149 struct nk_tt__edge *e;
10150 int n,i,j,k,m;
10151 int vsubsample = 1;
10152 /* vsubsample should divide 255 evenly; otherwise we won't reach full opacity */
10153
10154 /* now we have to blow out the windings into explicit edge lists */
10155 n = 0;
10156 for (i=0; i < windings; ++i)
10157 n += wcount[i];
10158
10159 e = (struct nk_tt__edge*)
10160 alloc->alloc(alloc->userdata, 0,(sizeof(*e) * (nk_size)(n+1)));
10161 if (e == 0) return;
10162 n = 0;
10163
10164 m=0;
10165 for (i=0; i < windings; ++i)
10166 {
10167 struct nk_tt__point *p = pts + m;
10168 m += wcount[i];
10169 j = wcount[i]-1;
10170 for (k=0; k < wcount[i]; j=k++) {
10171 int a=k,b=j;
10172 /* skip the edge if horizontal */
10173 if (p[j].y == p[k].y)
10174 continue;
10175
10176 /* add edge from j to k to the list */
10177 e[n].invert = 0;
10178 if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
10179 e[n].invert = 1;
10180 a=j,b=k;
10181 }
10182 e[n].x0 = p[a].x * scale_x + shift_x;
10183 e[n].y0 = (p[a].y * y_scale_inv + shift_y) * (float)vsubsample;
10184 e[n].x1 = p[b].x * scale_x + shift_x;
10185 e[n].y1 = (p[b].y * y_scale_inv + shift_y) * (float)vsubsample;
10186 ++n;
10187 }
10188 }
10189
10190 /* now sort the edges by their highest point (should snap to integer, and then by x) */
10191 /*STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); */
10192 nk_tt__sort_edges(e, n);
10193 /* now, traverse the scanlines and find the intersections on each scanline, use xor winding rule */
10194 nk_tt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, alloc);
10195 alloc->free(alloc->userdata, e);
10196}
10197
10198NK_INTERN void
10199nk_tt__add_point(struct nk_tt__point *points, int n, float x, float y)
10200{
10201 if (!points) return; /* during first pass, it's unallocated */
10202 points[n].x = x;
10203 points[n].y = y;
10204}
10205
10206NK_INTERN int
10207nk_tt__tesselate_curve(struct nk_tt__point *points, int *num_points,
10208 float x0, float y0, float x1, float y1, float x2, float y2,
10209 float objspace_flatness_squared, int n)
10210{
10211 /* tesselate until threshold p is happy...
10212 * @TODO warped to compensate for non-linear stretching */
10213 /* midpoint */
10214 float mx = (x0 + 2*x1 + x2)/4;
10215 float my = (y0 + 2*y1 + y2)/4;
10216 /* versus directly drawn line */
10217 float dx = (x0+x2)/2 - mx;
10218 float dy = (y0+y2)/2 - my;
10219 if (n > 16) /* 65536 segments on one curve better be enough! */
10220 return 1;
10221
10222 /* half-pixel error allowed... need to be smaller if AA */
10223 if (dx*dx+dy*dy > objspace_flatness_squared) {
10224 nk_tt__tesselate_curve(points, num_points, x0,y0,
10225 (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
10226 nk_tt__tesselate_curve(points, num_points, mx,my,
10227 (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
10228 } else {
10229 nk_tt__add_point(points, *num_points,x2,y2);
10230 *num_points = *num_points+1;
10231 }
10232 return 1;
10233}
10234
10235/* returns number of contours */
10236NK_INTERN struct nk_tt__point*
10237nk_tt_FlattenCurves(struct nk_tt_vertex *vertices, int num_verts,
10238 float objspace_flatness, int **contour_lengths, int *num_contours,
10239 struct nk_allocator *alloc)
10240{
10241 struct nk_tt__point *points=0;
10242 int num_points=0;
10243 float objspace_flatness_squared = objspace_flatness * objspace_flatness;
10244 int i;
10245 int n=0;
10246 int start=0;
10247 int pass;
10248
10249 /* count how many "moves" there are to get the contour count */
10250 for (i=0; i < num_verts; ++i)
10251 if (vertices[i].type == NK_TT_vmove) ++n;
10252
10253 *num_contours = n;
10254 if (n == 0) return 0;
10255
10256 *contour_lengths = (int *)
10257 alloc->alloc(alloc->userdata,0, (sizeof(**contour_lengths) * (nk_size)n));
10258 if (*contour_lengths == 0) {
10259 *num_contours = 0;
10260 return 0;
10261 }
10262
10263 /* make two passes through the points so we don't need to realloc */
10264 for (pass=0; pass < 2; ++pass)
10265 {
10266 float x=0,y=0;
10267 if (pass == 1) {
10268 points = (struct nk_tt__point *)
10269 alloc->alloc(alloc->userdata,0, (nk_size)num_points * sizeof(points[0]));
10270 if (points == 0) goto error;
10271 }
10272 num_points = 0;
10273 n= -1;
10274
10275 for (i=0; i < num_verts; ++i)
10276 {
10277 switch (vertices[i].type) {
10278 case NK_TT_vmove:
10279 /* start the next contour */
10280 if (n >= 0)
10281 (*contour_lengths)[n] = num_points - start;
10282 ++n;
10283 start = num_points;
10284
10285 x = vertices[i].x, y = vertices[i].y;
10286 nk_tt__add_point(points, num_points++, x,y);
10287 break;
10288 case NK_TT_vline:
10289 x = vertices[i].x, y = vertices[i].y;
10290 nk_tt__add_point(points, num_points++, x, y);
10291 break;
10292 case NK_TT_vcurve:
10293 nk_tt__tesselate_curve(points, &num_points, x,y,
10294 vertices[i].cx, vertices[i].cy,
10295 vertices[i].x, vertices[i].y,
10296 objspace_flatness_squared, 0);
10297 x = vertices[i].x, y = vertices[i].y;
10298 break;
10299 default: break;
10300 }
10301 }
10302 (*contour_lengths)[n] = num_points - start;
10303 }
10304 return points;
10305
10306error:
10307 alloc->free(alloc->userdata, points);
10308 alloc->free(alloc->userdata, *contour_lengths);
10309 *contour_lengths = 0;
10310 *num_contours = 0;
10311 return 0;
10312}
10313
10314NK_INTERN void
10315nk_tt_Rasterize(struct nk_tt__bitmap *result, float flatness_in_pixels,
10316 struct nk_tt_vertex *vertices, int num_verts,
10317 float scale_x, float scale_y, float shift_x, float shift_y,
10318 int x_off, int y_off, int invert, struct nk_allocator *alloc)
10319{
10320 float scale = scale_x > scale_y ? scale_y : scale_x;
10321 int winding_count, *winding_lengths;
10322 struct nk_tt__point *windings = nk_tt_FlattenCurves(vertices, num_verts,
10323 flatness_in_pixels / scale, &winding_lengths, &winding_count, alloc);
10324
10325 NK_ASSERT(alloc);
10326 if (windings) {
10327 nk_tt__rasterize(result, windings, winding_lengths, winding_count,
10328 scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, alloc);
10329 alloc->free(alloc->userdata, winding_lengths);
10330 alloc->free(alloc->userdata, windings);
10331 }
10332}
10333
10334NK_INTERN void
10335nk_tt_MakeGlyphBitmapSubpixel(const struct nk_tt_fontinfo *info, unsigned char *output,
10336 int out_w, int out_h, int out_stride, float scale_x, float scale_y,
10337 float shift_x, float shift_y, int glyph, struct nk_allocator *alloc)
10338{
10339 int ix0,iy0;
10340 struct nk_tt_vertex *vertices;
10341 int num_verts = nk_tt_GetGlyphShape(info, alloc, glyph, &vertices);
10342 struct nk_tt__bitmap gbm;
10343
10344 nk_tt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x,
10345 shift_y, &ix0,&iy0,0,0);
10346 gbm.pixels = output;
10347 gbm.w = out_w;
10348 gbm.h = out_h;
10349 gbm.stride = out_stride;
10350
10351 if (gbm.w && gbm.h)
10352 nk_tt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y,
10353 shift_x, shift_y, ix0,iy0, 1, alloc);
10354 alloc->free(alloc->userdata, vertices);
10355}
10356
10357/*-------------------------------------------------------------
10358 * Bitmap baking
10359 * --------------------------------------------------------------*/
10360NK_INTERN int
10361nk_tt_PackBegin(struct nk_tt_pack_context *spc, unsigned char *pixels,
10362 int pw, int ph, int stride_in_bytes, int padding, struct nk_allocator *alloc)
10363{
10364 int num_nodes = pw - padding;
10365 struct nk_rp_context *context = (struct nk_rp_context *)
10366 alloc->alloc(alloc->userdata,0, sizeof(*context));
10367 struct nk_rp_node *nodes = (struct nk_rp_node*)
10368 alloc->alloc(alloc->userdata,0, (sizeof(*nodes ) * (nk_size)num_nodes));
10369
10370 if (context == 0 || nodes == 0) {
10371 if (context != 0) alloc->free(alloc->userdata, context);
10372 if (nodes != 0) alloc->free(alloc->userdata, nodes);
10373 return 0;
10374 }
10375
10376 spc->width = pw;
10377 spc->height = ph;
10378 spc->pixels = pixels;
10379 spc->pack_info = context;
10380 spc->nodes = nodes;
10381 spc->padding = padding;
10382 spc->stride_in_bytes = (stride_in_bytes != 0) ? stride_in_bytes : pw;
10383 spc->h_oversample = 1;
10384 spc->v_oversample = 1;
10385
10386 nk_rp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
10387 if (pixels)
10388 NK_MEMSET(pixels, 0, (nk_size)(pw*ph)); /* background of 0 around pixels */
10389 return 1;
10390}
10391
10392NK_INTERN void
10393nk_tt_PackEnd(struct nk_tt_pack_context *spc, struct nk_allocator *alloc)
10394{
10395 alloc->free(alloc->userdata, spc->nodes);
10396 alloc->free(alloc->userdata, spc->pack_info);
10397}
10398
10399NK_INTERN void
10400nk_tt_PackSetOversampling(struct nk_tt_pack_context *spc,
10401 unsigned int h_oversample, unsigned int v_oversample)
10402{
10403 NK_ASSERT(h_oversample <= NK_TT_MAX_OVERSAMPLE);
10404 NK_ASSERT(v_oversample <= NK_TT_MAX_OVERSAMPLE);
10405 if (h_oversample <= NK_TT_MAX_OVERSAMPLE)
10406 spc->h_oversample = h_oversample;
10407 if (v_oversample <= NK_TT_MAX_OVERSAMPLE)
10408 spc->v_oversample = v_oversample;
10409}
10410
10411NK_INTERN void
10412nk_tt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes,
10413 int kernel_width)
10414{
10415 unsigned char buffer[NK_TT_MAX_OVERSAMPLE];
10416 int safe_w = w - kernel_width;
10417 int j;
10418
10419 for (j=0; j < h; ++j)
10420 {
10421 int i;
10422 unsigned int total;
10423 NK_MEMSET(buffer, 0, (nk_size)kernel_width);
10424
10425 total = 0;
10426
10427 /* make kernel_width a constant in common cases so compiler can optimize out the divide */
10428 switch (kernel_width) {
10429 case 2:
10430 for (i=0; i <= safe_w; ++i) {
10431 total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]);
10432 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10433 pixels[i] = (unsigned char) (total / 2);
10434 }
10435 break;
10436 case 3:
10437 for (i=0; i <= safe_w; ++i) {
10438 total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]);
10439 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10440 pixels[i] = (unsigned char) (total / 3);
10441 }
10442 break;
10443 case 4:
10444 for (i=0; i <= safe_w; ++i) {
10445 total += (unsigned int)pixels[i] - buffer[i & NK_TT__OVER_MASK];
10446 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10447 pixels[i] = (unsigned char) (total / 4);
10448 }
10449 break;
10450 case 5:
10451 for (i=0; i <= safe_w; ++i) {
10452 total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]);
10453 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10454 pixels[i] = (unsigned char) (total / 5);
10455 }
10456 break;
10457 default:
10458 for (i=0; i <= safe_w; ++i) {
10459 total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]);
10460 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10461 pixels[i] = (unsigned char) (total / (unsigned int)kernel_width);
10462 }
10463 break;
10464 }
10465
10466 for (; i < w; ++i) {
10467 NK_ASSERT(pixels[i] == 0);
10468 total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]);
10469 pixels[i] = (unsigned char) (total / (unsigned int)kernel_width);
10470 }
10471 pixels += stride_in_bytes;
10472 }
10473}
10474
10475NK_INTERN void
10476nk_tt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes,
10477 int kernel_width)
10478{
10479 unsigned char buffer[NK_TT_MAX_OVERSAMPLE];
10480 int safe_h = h - kernel_width;
10481 int j;
10482
10483 for (j=0; j < w; ++j)
10484 {
10485 int i;
10486 unsigned int total;
10487 NK_MEMSET(buffer, 0, (nk_size)kernel_width);
10488
10489 total = 0;
10490
10491 /* make kernel_width a constant in common cases so compiler can optimize out the divide */
10492 switch (kernel_width) {
10493 case 2:
10494 for (i=0; i <= safe_h; ++i) {
10495 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
10496 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
10497 pixels[i*stride_in_bytes] = (unsigned char) (total / 2);
10498 }
10499 break;
10500 case 3:
10501 for (i=0; i <= safe_h; ++i) {
10502 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
10503 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
10504 pixels[i*stride_in_bytes] = (unsigned char) (total / 3);
10505 }
10506 break;
10507 case 4:
10508 for (i=0; i <= safe_h; ++i) {
10509 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
10510 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
10511 pixels[i*stride_in_bytes] = (unsigned char) (total / 4);
10512 }
10513 break;
10514 case 5:
10515 for (i=0; i <= safe_h; ++i) {
10516 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
10517 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
10518 pixels[i*stride_in_bytes] = (unsigned char) (total / 5);
10519 }
10520 break;
10521 default:
10522 for (i=0; i <= safe_h; ++i) {
10523 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
10524 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
10525 pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width);
10526 }
10527 break;
10528 }
10529
10530 for (; i < h; ++i) {
10531 NK_ASSERT(pixels[i*stride_in_bytes] == 0);
10532 total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]);
10533 pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width);
10534 }
10535 pixels += 1;
10536 }
10537}
10538
10539NK_INTERN float
10540nk_tt__oversample_shift(int oversample)
10541{
10542 if (!oversample)
10543 return 0.0f;
10544
10545 /* The prefilter is a box filter of width "oversample", */
10546 /* which shifts phase by (oversample - 1)/2 pixels in */
10547 /* oversampled space. We want to shift in the opposite */
10548 /* direction to counter this. */
10549 return (float)-(oversample - 1) / (2.0f * (float)oversample);
10550}
10551
10552/* rects array must be big enough to accommodate all characters in the given ranges */
10553NK_INTERN int
10554nk_tt_PackFontRangesGatherRects(struct nk_tt_pack_context *spc,
10555 struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges,
10556 int num_ranges, struct nk_rp_rect *rects)
10557{
10558 int i,j,k;
10559 k = 0;
10560
10561 for (i=0; i < num_ranges; ++i) {
10562 float fh = ranges[i].font_size;
10563 float scale = (fh > 0) ? nk_tt_ScaleForPixelHeight(info, fh):
10564 nk_tt_ScaleForMappingEmToPixels(info, -fh);
10565 ranges[i].h_oversample = (unsigned char) spc->h_oversample;
10566 ranges[i].v_oversample = (unsigned char) spc->v_oversample;
10567 for (j=0; j < ranges[i].num_chars; ++j) {
10568 int x0,y0,x1,y1;
10569 int codepoint = ranges[i].first_unicode_codepoint_in_range ?
10570 ranges[i].first_unicode_codepoint_in_range + j :
10571 ranges[i].array_of_unicode_codepoints[j];
10572
10573 int glyph = nk_tt_FindGlyphIndex(info, codepoint);
10574 nk_tt_GetGlyphBitmapBoxSubpixel(info,glyph, scale * (float)spc->h_oversample,
10575 scale * (float)spc->v_oversample, 0,0, &x0,&y0,&x1,&y1);
10576 rects[k].w = (nk_rp_coord) (x1-x0 + spc->padding + (int)spc->h_oversample-1);
10577 rects[k].h = (nk_rp_coord) (y1-y0 + spc->padding + (int)spc->v_oversample-1);
10578 ++k;
10579 }
10580 }
10581 return k;
10582}
10583
10584NK_INTERN int
10585nk_tt_PackFontRangesRenderIntoRects(struct nk_tt_pack_context *spc,
10586 struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges,
10587 int num_ranges, struct nk_rp_rect *rects, struct nk_allocator *alloc)
10588{
10589 int i,j,k, return_value = 1;
10590 /* save current values */
10591 int old_h_over = (int)spc->h_oversample;
10592 int old_v_over = (int)spc->v_oversample;
10593 /* rects array must be big enough to accommodate all characters in the given ranges */
10594
10595 k = 0;
10596 for (i=0; i < num_ranges; ++i)
10597 {
10598 float fh = ranges[i].font_size;
10599 float recip_h,recip_v,sub_x,sub_y;
10600 float scale = fh > 0 ? nk_tt_ScaleForPixelHeight(info, fh):
10601 nk_tt_ScaleForMappingEmToPixels(info, -fh);
10602
10603 spc->h_oversample = ranges[i].h_oversample;
10604 spc->v_oversample = ranges[i].v_oversample;
10605
10606 recip_h = 1.0f / (float)spc->h_oversample;
10607 recip_v = 1.0f / (float)spc->v_oversample;
10608
10609 sub_x = nk_tt__oversample_shift((int)spc->h_oversample);
10610 sub_y = nk_tt__oversample_shift((int)spc->v_oversample);
10611
10612 for (j=0; j < ranges[i].num_chars; ++j)
10613 {
10614 struct nk_rp_rect *r = &rects[k];
10615 if (r->was_packed)
10616 {
10617 struct nk_tt_packedchar *bc = &ranges[i].chardata_for_range[j];
10618 int advance, lsb, x0,y0,x1,y1;
10619 int codepoint = ranges[i].first_unicode_codepoint_in_range ?
10620 ranges[i].first_unicode_codepoint_in_range + j :
10621 ranges[i].array_of_unicode_codepoints[j];
10622 int glyph = nk_tt_FindGlyphIndex(info, codepoint);
10623 nk_rp_coord pad = (nk_rp_coord) spc->padding;
10624
10625 /* pad on left and top */
10626 r->x = (nk_rp_coord)((int)r->x + (int)pad);
10627 r->y = (nk_rp_coord)((int)r->y + (int)pad);
10628 r->w = (nk_rp_coord)((int)r->w - (int)pad);
10629 r->h = (nk_rp_coord)((int)r->h - (int)pad);
10630
10631 nk_tt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
10632 nk_tt_GetGlyphBitmapBox(info, glyph, scale * (float)spc->h_oversample,
10633 (scale * (float)spc->v_oversample), &x0,&y0,&x1,&y1);
10634 nk_tt_MakeGlyphBitmapSubpixel(info, spc->pixels + r->x + r->y*spc->stride_in_bytes,
10635 (int)(r->w - spc->h_oversample+1), (int)(r->h - spc->v_oversample+1),
10636 spc->stride_in_bytes, scale * (float)spc->h_oversample,
10637 scale * (float)spc->v_oversample, 0,0, glyph, alloc);
10638
10639 if (spc->h_oversample > 1)
10640 nk_tt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
10641 r->w, r->h, spc->stride_in_bytes, (int)spc->h_oversample);
10642
10643 if (spc->v_oversample > 1)
10644 nk_tt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
10645 r->w, r->h, spc->stride_in_bytes, (int)spc->v_oversample);
10646
10647 bc->x0 = (nk_ushort) r->x;
10648 bc->y0 = (nk_ushort) r->y;
10649 bc->x1 = (nk_ushort) (r->x + r->w);
10650 bc->y1 = (nk_ushort) (r->y + r->h);
10651 bc->xadvance = scale * (float)advance;
10652 bc->xoff = (float) x0 * recip_h + sub_x;
10653 bc->yoff = (float) y0 * recip_v + sub_y;
10654 bc->xoff2 = ((float)x0 + r->w) * recip_h + sub_x;
10655 bc->yoff2 = ((float)y0 + r->h) * recip_v + sub_y;
10656 } else {
10657 return_value = 0; /* if any fail, report failure */
10658 }
10659 ++k;
10660 }
10661 }
10662 /* restore original values */
10663 spc->h_oversample = (unsigned int)old_h_over;
10664 spc->v_oversample = (unsigned int)old_v_over;
10665 return return_value;
10666}
10667
10668NK_INTERN void
10669nk_tt_GetPackedQuad(struct nk_tt_packedchar *chardata, int pw, int ph,
10670 int char_index, float *xpos, float *ypos, struct nk_tt_aligned_quad *q,
10671 int align_to_integer)
10672{
10673 float ipw = 1.0f / (float)pw, iph = 1.0f / (float)ph;
10674 struct nk_tt_packedchar *b = (struct nk_tt_packedchar*)(chardata + char_index);
10675 if (align_to_integer) {
10676 int tx = nk_ifloorf((*xpos + b->xoff) + 0.5f);
10677 int ty = nk_ifloorf((*ypos + b->yoff) + 0.5f);
10678
10679 float x = (float)tx;
10680 float y = (float)ty;
10681
10682 q->x0 = x;
10683 q->y0 = y;
10684 q->x1 = x + b->xoff2 - b->xoff;
10685 q->y1 = y + b->yoff2 - b->yoff;
10686 } else {
10687 q->x0 = *xpos + b->xoff;
10688 q->y0 = *ypos + b->yoff;
10689 q->x1 = *xpos + b->xoff2;
10690 q->y1 = *ypos + b->yoff2;
10691 }
10692 q->s0 = b->x0 * ipw;
10693 q->t0 = b->y0 * iph;
10694 q->s1 = b->x1 * ipw;
10695 q->t1 = b->y1 * iph;
10696 *xpos += b->xadvance;
10697}
10698
10699/* -------------------------------------------------------------
10700 *
10701 * FONT BAKING
10702 *
10703 * --------------------------------------------------------------*/
10704struct nk_font_bake_data {
10705 struct nk_tt_fontinfo info;
10706 struct nk_rp_rect *rects;
10707 struct nk_tt_pack_range *ranges;
10708 nk_rune range_count;
10709};
10710
10711struct nk_font_baker {
10712 struct nk_allocator alloc;
10713 struct nk_tt_pack_context spc;
10714 struct nk_font_bake_data *build;
10715 struct nk_tt_packedchar *packed_chars;
10716 struct nk_rp_rect *rects;
10717 struct nk_tt_pack_range *ranges;
10718};
10719
10720NK_GLOBAL const nk_size nk_rect_align = NK_ALIGNOF(struct nk_rp_rect);
10721NK_GLOBAL const nk_size nk_range_align = NK_ALIGNOF(struct nk_tt_pack_range);
10722NK_GLOBAL const nk_size nk_char_align = NK_ALIGNOF(struct nk_tt_packedchar);
10723NK_GLOBAL const nk_size nk_build_align = NK_ALIGNOF(struct nk_font_bake_data);
10724NK_GLOBAL const nk_size nk_baker_align = NK_ALIGNOF(struct nk_font_baker);
10725
10726NK_INTERN int
10727nk_range_count(const nk_rune *range)
10728{
10729 const nk_rune *iter = range;
10730 NK_ASSERT(range);
10731 if (!range) return 0;
10732 while (*(iter++) != 0);
10733 return (iter == range) ? 0 : (int)((iter - range)/2);
10734}
10735
10736NK_INTERN int
10737nk_range_glyph_count(const nk_rune *range, int count)
10738{
10739 int i = 0;
10740 int total_glyphs = 0;
10741 for (i = 0; i < count; ++i) {
10742 int diff;
10743 nk_rune f = range[(i*2)+0];
10744 nk_rune t = range[(i*2)+1];
10745 NK_ASSERT(t >= f);
10746 diff = (int)((t - f) + 1);
10747 total_glyphs += diff;
10748 }
10749 return total_glyphs;
10750}
10751
10752NK_API const nk_rune*
10753nk_font_default_glyph_ranges(void)
10754{
10755 NK_STORAGE const nk_rune ranges[] = {0x0020, 0x00FF, 0};
10756 return ranges;
10757}
10758
10759NK_API const nk_rune*
10760nk_font_chinese_glyph_ranges(void)
10761{
10762 NK_STORAGE const nk_rune ranges[] = {
10763 0x0020, 0x00FF,
10764 0x3000, 0x30FF,
10765 0x31F0, 0x31FF,
10766 0xFF00, 0xFFEF,
10767 0x4e00, 0x9FAF,
10768 0
10769 };
10770 return ranges;
10771}
10772
10773NK_API const nk_rune*
10774nk_font_cyrillic_glyph_ranges(void)
10775{
10776 NK_STORAGE const nk_rune ranges[] = {
10777 0x0020, 0x00FF,
10778 0x0400, 0x052F,
10779 0x2DE0, 0x2DFF,
10780 0xA640, 0xA69F,
10781 0
10782 };
10783 return ranges;
10784}
10785
10786NK_API const nk_rune*
10787nk_font_korean_glyph_ranges(void)
10788{
10789 NK_STORAGE const nk_rune ranges[] = {
10790 0x0020, 0x00FF,
10791 0x3131, 0x3163,
10792 0xAC00, 0xD79D,
10793 0
10794 };
10795 return ranges;
10796}
10797
10798NK_INTERN void
10799nk_font_baker_memory(nk_size *temp, int *glyph_count,
10800 struct nk_font_config *config_list, int count)
10801{
10802 int range_count = 0;
10803 int total_range_count = 0;
10804 struct nk_font_config *iter;
10805
10806 NK_ASSERT(config_list);
10807 NK_ASSERT(glyph_count);
10808 if (!config_list) {
10809 *temp = 0;
10810 *glyph_count = 0;
10811 return;
10812 }
10813
10814 *glyph_count = 0;
10815 if (!config_list->range)
10816 config_list->range = nk_font_default_glyph_ranges();
10817 for (iter = config_list; iter; iter = iter->next) {
10818 range_count = nk_range_count(iter->range);
10819 total_range_count += range_count;
10820 *glyph_count += nk_range_glyph_count(iter->range, range_count);
10821 }
10822
10823 *temp = (nk_size)*glyph_count * sizeof(struct nk_rp_rect);
10824 *temp += (nk_size)total_range_count * sizeof(struct nk_tt_pack_range);
10825 *temp += (nk_size)*glyph_count * sizeof(struct nk_tt_packedchar);
10826 *temp += (nk_size)count * sizeof(struct nk_font_bake_data);
10827 *temp += sizeof(struct nk_font_baker);
10828 *temp += nk_rect_align + nk_range_align + nk_char_align;
10829 *temp += nk_build_align + nk_baker_align;
10830}
10831
10832NK_INTERN struct nk_font_baker*
10833nk_font_baker(void *memory, int glyph_count, int count, struct nk_allocator *alloc)
10834{
10835 struct nk_font_baker *baker;
10836 if (!memory) return 0;
10837 /* setup baker inside a memory block */
10838 baker = (struct nk_font_baker*)NK_ALIGN_PTR(memory, nk_baker_align);
10839 baker->build = (struct nk_font_bake_data*)NK_ALIGN_PTR((baker + 1), nk_build_align);
10840 baker->packed_chars = (struct nk_tt_packedchar*)NK_ALIGN_PTR((baker->build + count), nk_char_align);
10841 baker->rects = (struct nk_rp_rect*)NK_ALIGN_PTR((baker->packed_chars + glyph_count), nk_rect_align);
10842 baker->ranges = (struct nk_tt_pack_range*)NK_ALIGN_PTR((baker->rects + glyph_count), nk_range_align);
10843 baker->alloc = *alloc;
10844 return baker;
10845}
10846
10847NK_INTERN int
10848nk_font_bake_pack(struct nk_font_baker *baker,
10849 nk_size *image_memory, int *width, int *height, struct nk_recti *custom,
10850 const struct nk_font_config *config_list, int count,
10851 struct nk_allocator *alloc)
10852{
10853 NK_STORAGE const nk_size max_height = 1024 * 32;
10854 const struct nk_font_config *config_iter;
10855 int total_glyph_count = 0;
10856 int total_range_count = 0;
10857 int range_count = 0;
10858 int i = 0;
10859
10860 NK_ASSERT(image_memory);
10861 NK_ASSERT(width);
10862 NK_ASSERT(height);
10863 NK_ASSERT(config_list);
10864 NK_ASSERT(count);
10865 NK_ASSERT(alloc);
10866
10867 if (!image_memory || !width || !height || !config_list || !count) return nk_false;
10868 for (config_iter = config_list; config_iter; config_iter = config_iter->next) {
10869 range_count = nk_range_count(config_iter->range);
10870 total_range_count += range_count;
10871 total_glyph_count += nk_range_glyph_count(config_iter->range, range_count);
10872 }
10873
10874 /* setup font baker from temporary memory */
10875 for (config_iter = config_list; config_iter; config_iter = config_iter->next) {
10876 const struct nk_font_config *cfg = config_iter;
10877 if (!nk_tt_InitFont(&baker->build[i++].info, (const unsigned char*)cfg->ttf_blob, 0))
10878 return nk_false;
10879 }
10880
10881 *height = 0;
10882 *width = (total_glyph_count > 1000) ? 1024 : 512;
10883 nk_tt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, alloc);
10884 {
10885 int input_i = 0;
10886 int range_n = 0;
10887 int rect_n = 0;
10888 int char_n = 0;
10889
10890 if (custom) {
10891 /* pack custom user data first so it will be in the upper left corner*/
10892 struct nk_rp_rect custom_space;
10893 nk_zero(&custom_space, sizeof(custom_space));
10894 custom_space.w = (nk_rp_coord)((custom->w * 2) + 1);
10895 custom_space.h = (nk_rp_coord)(custom->h + 1);
10896
10897 nk_tt_PackSetOversampling(&baker->spc, 1, 1);
10898 nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, &custom_space, 1);
10899 *height = NK_MAX(*height, (int)(custom_space.y + custom_space.h));
10900
10901 custom->x = (short)custom_space.x;
10902 custom->y = (short)custom_space.y;
10903 custom->w = (short)custom_space.w;
10904 custom->h = (short)custom_space.h;
10905 }
10906
10907 /* first font pass: pack all glyphs */
10908 for (input_i = 0, config_iter = config_list; input_i < count && config_iter;
10909 input_i++, config_iter = config_iter->next)
10910 {
10911 int n = 0;
10912 int glyph_count;
10913 const nk_rune *in_range;
10914 const struct nk_font_config *cfg = config_iter;
10915 struct nk_font_bake_data *tmp = &baker->build[input_i];
10916
10917 /* count glyphs + ranges in current font */
10918 glyph_count = 0; range_count = 0;
10919 for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) {
10920 glyph_count += (int)(in_range[1] - in_range[0]) + 1;
10921 range_count++;
10922 }
10923
10924 /* setup ranges */
10925 tmp->ranges = baker->ranges + range_n;
10926 tmp->range_count = (nk_rune)range_count;
10927 range_n += range_count;
10928 for (i = 0; i < range_count; ++i) {
10929 in_range = &cfg->range[i * 2];
10930 tmp->ranges[i].font_size = cfg->size;
10931 tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0];
10932 tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1;
10933 tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n;
10934 char_n += tmp->ranges[i].num_chars;
10935 }
10936
10937 /* pack */
10938 tmp->rects = baker->rects + rect_n;
10939 rect_n += glyph_count;
10940 nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);
10941 n = nk_tt_PackFontRangesGatherRects(&baker->spc, &tmp->info,
10942 tmp->ranges, (int)tmp->range_count, tmp->rects);
10943 nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, tmp->rects, (int)n);
10944
10945 /* texture height */
10946 for (i = 0; i < n; ++i) {
10947 if (tmp->rects[i].was_packed)
10948 *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h);
10949 }
10950 }
10951 NK_ASSERT(rect_n == total_glyph_count);
10952 NK_ASSERT(char_n == total_glyph_count);
10953 NK_ASSERT(range_n == total_range_count);
10954 }
10955 *height = (int)nk_round_up_pow2((nk_uint)*height);
10956 *image_memory = (nk_size)(*width) * (nk_size)(*height);
10957 return nk_true;
10958}
10959
10960NK_INTERN void
10961nk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int height,
10962 struct nk_font_glyph *glyphs, int glyphs_count,
10963 const struct nk_font_config *config_list, int font_count)
10964{
10965 int input_i = 0;
10966 nk_rune glyph_n = 0;
10967 const struct nk_font_config *config_iter;
10968
10969 NK_ASSERT(image_memory);
10970 NK_ASSERT(width);
10971 NK_ASSERT(height);
10972 NK_ASSERT(config_list);
10973 NK_ASSERT(baker);
10974 NK_ASSERT(font_count);
10975 NK_ASSERT(glyphs_count);
10976 if (!image_memory || !width || !height || !config_list ||
10977 !font_count || !glyphs || !glyphs_count)
10978 return;
10979
10980 /* second font pass: render glyphs */
10981 nk_zero(image_memory, (nk_size)((nk_size)width * (nk_size)height));
10982 baker->spc.pixels = (unsigned char*)image_memory;
10983 baker->spc.height = (int)height;
10984 for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;
10985 ++input_i, config_iter = config_iter->next)
10986 {
10987 const struct nk_font_config *cfg = config_iter;
10988 struct nk_font_bake_data *tmp = &baker->build[input_i];
10989 nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);
10990 nk_tt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges,
10991 (int)tmp->range_count, tmp->rects, &baker->alloc);
10992 }
10993 nk_tt_PackEnd(&baker->spc, &baker->alloc);
10994
10995 /* third pass: setup font and glyphs */
10996 for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;
10997 ++input_i, config_iter = config_iter->next)
10998 {
10999 nk_size i = 0;
11000 int char_idx = 0;
11001 nk_rune glyph_count = 0;
11002 const struct nk_font_config *cfg = config_iter;
11003 struct nk_font_bake_data *tmp = &baker->build[input_i];
11004 struct nk_baked_font *dst_font = cfg->font;
11005
11006 float font_scale = nk_tt_ScaleForPixelHeight(&tmp->info, cfg->size);
11007 int unscaled_ascent, unscaled_descent, unscaled_line_gap;
11008 nk_tt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent,
11009 &unscaled_line_gap);
11010
11011 /* fill baked font */
11012 if (!cfg->merge_mode) {
11013 dst_font->ranges = cfg->range;
11014 dst_font->height = cfg->size;
11015 dst_font->ascent = ((float)unscaled_ascent * font_scale);
11016 dst_font->descent = ((float)unscaled_descent * font_scale);
11017 dst_font->glyph_offset = glyph_n;
11018 }
11019
11020 /* fill own baked font glyph array */
11021 for (i = 0; i < tmp->range_count; ++i)
11022 {
11023 struct nk_tt_pack_range *range = &tmp->ranges[i];
11024 for (char_idx = 0; char_idx < range->num_chars; char_idx++)
11025 {
11026 nk_rune codepoint = 0;
11027 float dummy_x = 0, dummy_y = 0;
11028 struct nk_tt_aligned_quad q;
11029 struct nk_font_glyph *glyph;
11030
11031 /* query glyph bounds from stb_truetype */
11032 const struct nk_tt_packedchar *pc = &range->chardata_for_range[char_idx];
11033 if (!pc->x0 && !pc->x1 && !pc->y0 && !pc->y1) continue;
11034 codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx);
11035 nk_tt_GetPackedQuad(range->chardata_for_range, (int)width,
11036 (int)height, char_idx, &dummy_x, &dummy_y, &q, 0);
11037
11038 /* fill own glyph type with data */
11039 glyph = &glyphs[dst_font->glyph_offset + (unsigned int)glyph_count];
11040 glyph->codepoint = codepoint;
11041 glyph->x0 = q.x0; glyph->y0 = q.y0;
11042 glyph->x1 = q.x1; glyph->y1 = q.y1;
11043 glyph->y0 += (dst_font->ascent + 0.5f);
11044 glyph->y1 += (dst_font->ascent + 0.5f);
11045 glyph->w = glyph->x1 - glyph->x0 + 0.5f;
11046 glyph->h = glyph->y1 - glyph->y0;
11047
11048 if (cfg->coord_type == NK_COORD_PIXEL) {
11049 glyph->u0 = q.s0 * (float)width;
11050 glyph->v0 = q.t0 * (float)height;
11051 glyph->u1 = q.s1 * (float)width;
11052 glyph->v1 = q.t1 * (float)height;
11053 } else {
11054 glyph->u0 = q.s0;
11055 glyph->v0 = q.t0;
11056 glyph->u1 = q.s1;
11057 glyph->v1 = q.t1;
11058 }
11059 glyph->xadvance = (pc->xadvance + cfg->spacing.x);
11060 if (cfg->pixel_snap)
11061 glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f);
11062 glyph_count++;
11063 }
11064 }
11065 dst_font->glyph_count = glyph_count;
11066 glyph_n += dst_font->glyph_count;
11067 }
11068}
11069
11070NK_INTERN void
11071nk_font_bake_custom_data(void *img_memory, int img_width, int img_height,
11072 struct nk_recti img_dst, const char *texture_data_mask, int tex_width,
11073 int tex_height, char white, char black)
11074{
11075 nk_byte *pixels;
11076 int y = 0;
11077 int x = 0;
11078 int n = 0;
11079
11080 NK_ASSERT(img_memory);
11081 NK_ASSERT(img_width);
11082 NK_ASSERT(img_height);
11083 NK_ASSERT(texture_data_mask);
11084 NK_UNUSED(tex_height);
11085 if (!img_memory || !img_width || !img_height || !texture_data_mask)
11086 return;
11087
11088 pixels = (nk_byte*)img_memory;
11089 for (y = 0, n = 0; y < tex_height; ++y) {
11090 for (x = 0; x < tex_width; ++x, ++n) {
11091 const int off0 = ((img_dst.x + x) + (img_dst.y + y) * img_width);
11092 const int off1 = off0 + 1 + tex_width;
11093 pixels[off0] = (texture_data_mask[n] == white) ? 0xFF : 0x00;
11094 pixels[off1] = (texture_data_mask[n] == black) ? 0xFF : 0x00;
11095 }
11096 }
11097}
11098
11099NK_INTERN void
11100nk_font_bake_convert(void *out_memory, int img_width, int img_height,
11101 const void *in_memory)
11102{
11103 int n = 0;
11104 nk_rune *dst;
11105 const nk_byte *src;
11106
11107 NK_ASSERT(out_memory);
11108 NK_ASSERT(in_memory);
11109 NK_ASSERT(img_width);
11110 NK_ASSERT(img_height);
11111 if (!out_memory || !in_memory || !img_height || !img_width) return;
11112
11113 dst = (nk_rune*)out_memory;
11114 src = (const nk_byte*)in_memory;
11115 for (n = (int)(img_width * img_height); n > 0; n--)
11116 *dst++ = ((nk_rune)(*src++) << 24) | 0x00FFFFFF;
11117}
11118
11119/* -------------------------------------------------------------
11120 *
11121 * FONT
11122 *
11123 * --------------------------------------------------------------*/
11124NK_INTERN float
11125nk_font_text_width(nk_handle handle, float height, const char *text, int len)
11126{
11127 nk_rune unicode;
11128 int text_len = 0;
11129 float text_width = 0;
11130 int glyph_len = 0;
11131 float scale = 0;
11132
11133 struct nk_font *font = (struct nk_font*)handle.ptr;
11134 NK_ASSERT(font);
11135 NK_ASSERT(font->glyphs);
11136 if (!font || !text || !len)
11137 return 0;
11138
11139 scale = height/font->info.height;
11140 glyph_len = text_len = nk_utf_decode(text, &unicode, (int)len);
11141 if (!glyph_len) return 0;
11142 while (text_len <= (int)len && glyph_len) {
11143 const struct nk_font_glyph *g;
11144 if (unicode == NK_UTF_INVALID) break;
11145
11146 /* query currently drawn glyph information */
11147 g = nk_font_find_glyph(font, unicode);
11148 text_width += g->xadvance * scale;
11149
11150 /* offset next glyph */
11151 glyph_len = nk_utf_decode(text + text_len, &unicode, (int)len - text_len);
11152 text_len += glyph_len;
11153 }
11154 return text_width;
11155}
11156
11157#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
11158NK_INTERN void
11159nk_font_query_font_glyph(nk_handle handle, float height,
11160 struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)
11161{
11162 float scale;
11163 const struct nk_font_glyph *g;
11164 struct nk_font *font;
11165
11166 NK_ASSERT(glyph);
11167 NK_UNUSED(next_codepoint);
11168
11169 font = (struct nk_font*)handle.ptr;
11170 NK_ASSERT(font);
11171 NK_ASSERT(font->glyphs);
11172 if (!font || !glyph)
11173 return;
11174
11175 scale = height/font->info.height;
11176 g = nk_font_find_glyph(font, codepoint);
11177 glyph->width = (g->x1 - g->x0) * scale;
11178 glyph->height = (g->y1 - g->y0) * scale;
11179 glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale);
11180 glyph->xadvance = (g->xadvance * scale);
11181 glyph->uv[0] = nk_vec2(g->u0, g->v0);
11182 glyph->uv[1] = nk_vec2(g->u1, g->v1);
11183}
11184#endif
11185
11186NK_API const struct nk_font_glyph*
11187nk_font_find_glyph(struct nk_font *font, nk_rune unicode)
11188{
11189 int i = 0;
11190 int count;
11191 int total_glyphs = 0;
11192 const struct nk_font_glyph *glyph = 0;
11193
11194 NK_ASSERT(font);
11195 NK_ASSERT(font->glyphs);
11196 NK_ASSERT(font->info.ranges);
11197 if (!font || !font->glyphs) return 0;
11198
11199 glyph = font->fallback;
11200 count = nk_range_count(font->info.ranges);
11201 for (i = 0; i < count; ++i) {
11202 int diff;
11203 nk_rune f = font->info.ranges[(i*2)+0];
11204 nk_rune t = font->info.ranges[(i*2)+1];
11205 diff = (int)((t - f) + 1);
11206 if (unicode >= f && unicode <= t)
11207 return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))];
11208 total_glyphs += diff;
11209 }
11210 return glyph;
11211}
11212
11213NK_INTERN void
11214nk_font_init(struct nk_font *font, float pixel_height,
11215 nk_rune fallback_codepoint, struct nk_font_glyph *glyphs,
11216 const struct nk_baked_font *baked_font, nk_handle atlas)
11217{
11218 struct nk_baked_font baked;
11219 NK_ASSERT(font);
11220 NK_ASSERT(glyphs);
11221 NK_ASSERT(baked_font);
11222 if (!font || !glyphs || !baked_font)
11223 return;
11224
11225 baked = *baked_font;
11226 font->info = baked;
11227 font->scale = (float)pixel_height / (float)font->info.height;
11228 font->glyphs = &glyphs[baked_font->glyph_offset];
11229 font->texture = atlas;
11230 font->fallback_codepoint = fallback_codepoint;
11231 font->fallback = nk_font_find_glyph(font, fallback_codepoint);
11232
11233 font->handle.height = font->info.height * font->scale;
11234 font->handle.width = nk_font_text_width;
11235 font->handle.userdata.ptr = font;
11236#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
11237 font->handle.query = nk_font_query_font_glyph;
11238 font->handle.texture = font->texture;
11239#endif
11240}
11241
11242/* ---------------------------------------------------------------------------
11243 *
11244 * DEFAULT FONT
11245 *
11246 * ProggyClean.ttf
11247 * Copyright (c) 2004, 2005 Tristan Grimmer
11248 * MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
11249 * Download and more information at http://upperbounds.net
11250 *-----------------------------------------------------------------------------*/
11251#ifdef NK_INCLUDE_DEFAULT_FONT
11252
11253 #ifdef __clang__
11254#pragma clang diagnostic push
11255
11256#pragma clang diagnostic ignored "-Woverlength-strings"
11257#elif defined(__GNUC__) || defined(__GNUG__)
11258#pragma GCC diagnostic push
11259#pragma GCC diagnostic ignored "-Woverlength-strings"
11260#endif
11261
11262NK_GLOBAL const char nk_proggy_clean_ttf_compressed_data_base85[11980+1] =
11263 "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
11264 "2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#"
11265 "`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#0X@U.a<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL"
11266 "i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N"
11267 "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N"
11268 "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)"
11269 "tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX"
11270 "ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc."
11271 "x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G"
11272 "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)"
11273 "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#"
11274 "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM"
11275 "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu"
11276 "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/"
11277 "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L"
11278 "%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#"
11279 "OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)("
11280 "h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h"
11281 "o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO"
11282 "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-"
11283 "sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-"
11284 "eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO"
11285 "M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%"
11286 "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]"
11287 "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et"
11288 "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:"
11289 "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL("
11290 "$/V,;(kXZejWO`<[5?\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<iaQjO@.kLg;x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<"
11291 "nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?"
11292 "7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;"
11293 ")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M"
11294 "D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX("
11295 "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs"
11296 "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
11297 "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-"
11298 "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i"
11299 "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7"
11300 ".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@"
11301 "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*"
11302 "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u"
11303 "@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#"
11304 "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#"
11305 "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0"
11306 "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8"
11307 "6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#"
11308 "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD"
11309 ":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+"
11310 "tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*"
11311 "$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7"
11312 ":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A"
11313 "7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7"
11314 "u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT"
11315 "LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M"
11316 ":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>"
11317 "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%"
11318 "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;"
11319 "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:"
11320 "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%"
11321 "9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-"
11322 "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*"
11323 "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY"
11324 "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
11325 "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`"
11326 "0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/"
11327 "+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj"
11328 "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V"
11329 "?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK"
11330 "Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa"
11331 ">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>"
11332 "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I"
11333 "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#"
11334 "Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$"
11335 "MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)"
11336 "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo"
11337 "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P"
11338 "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO"
11339 "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#"
11340 ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>"
11341 "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#"
11342 "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4"
11343 "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#"
11344 "/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#"
11345 "m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#"
11346 "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
11347 "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
11348 "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
11349#endif /* NK_INCLUDE_DEFAULT_FONT */
11350
11351#define NK_CURSOR_DATA_W 90
11352#define NK_CURSOR_DATA_H 27
11353NK_GLOBAL const char nk_custom_cursor_data[NK_CURSOR_DATA_W * NK_CURSOR_DATA_H + 1] =
11354{
11355 "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX"
11356 "..- -X.....X- X.X - X.X -X.....X - X.....X"
11357 "--- -XXX.XXX- X...X - X...X -X....X - X....X"
11358 "X - X.X - X.....X - X.....X -X...X - X...X"
11359 "XX - X.X -X.......X- X.......X -X..X.X - X.X..X"
11360 "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X"
11361 "X..X - X.X - X.X - X.X -XX X.X - X.X XX"
11362 "X...X - X.X - X.X - XX X.X XX - X.X - X.X "
11363 "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X "
11364 "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X "
11365 "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X "
11366 "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X "
11367 "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X "
11368 "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X "
11369 "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X "
11370 "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X "
11371 "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX "
11372 "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------"
11373 "X.X X..X - -X.......X- X.......X - XX XX - "
11374 "XX X..X - - X.....X - X.....X - X.X X.X - "
11375 " X..X - X...X - X...X - X..X X..X - "
11376 " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - "
11377 "------------ - X - X -X.....................X- "
11378 " ----------------------------------- X...XXXXXXXXXXXXX...X - "
11379 " - X..X X..X - "
11380 " - X.X X.X - "
11381 " - XX XX - "
11382};
11383
11384#ifdef __clang__
11385#pragma clang diagnostic pop
11386#elif defined(__GNUC__) || defined(__GNUG__)
11387#pragma GCC diagnostic pop
11388#endif
11389
11390NK_INTERN unsigned int
11391nk_decompress_length(unsigned char *input)
11392{
11393 return (unsigned int)((input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]);
11394}
11395
11396NK_GLOBAL unsigned char *nk__barrier;
11397NK_GLOBAL unsigned char *nk__barrier2;
11398NK_GLOBAL unsigned char *nk__barrier3;
11399NK_GLOBAL unsigned char *nk__barrier4;
11400NK_GLOBAL unsigned char *nk__dout;
11401
11402NK_INTERN void
11403nk__match(unsigned char *data, unsigned int length)
11404{
11405 /* INVERSE of memmove... write each byte before copying the next...*/
11406 NK_ASSERT (nk__dout + length <= nk__barrier);
11407 if (nk__dout + length > nk__barrier) { nk__dout += length; return; }
11408 if (data < nk__barrier4) { nk__dout = nk__barrier+1; return; }
11409 while (length--) *nk__dout++ = *data++;
11410}
11411
11412NK_INTERN void
11413nk__lit(unsigned char *data, unsigned int length)
11414{
11415 NK_ASSERT (nk__dout + length <= nk__barrier);
11416 if (nk__dout + length > nk__barrier) { nk__dout += length; return; }
11417 if (data < nk__barrier2) { nk__dout = nk__barrier+1; return; }
11418 NK_MEMCPY(nk__dout, data, length);
11419 nk__dout += length;
11420}
11421
11422#define nk__in2(x) ((i[x] << 8) + i[(x)+1])
11423#define nk__in3(x) ((i[x] << 16) + nk__in2((x)+1))
11424#define nk__in4(x) ((i[x] << 24) + nk__in3((x)+1))
11425
11426NK_INTERN unsigned char*
11427nk_decompress_token(unsigned char *i)
11428{
11429 if (*i >= 0x20) { /* use fewer if's for cases that expand small */
11430 if (*i >= 0x80) nk__match(nk__dout-i[1]-1, (unsigned int)i[0] - 0x80 + 1), i += 2;
11431 else if (*i >= 0x40) nk__match(nk__dout-(nk__in2(0) - 0x4000 + 1), (unsigned int)i[2]+1), i += 3;
11432 else /* *i >= 0x20 */ nk__lit(i+1, (unsigned int)i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
11433 } else { /* more ifs for cases that expand large, since overhead is amortized */
11434 if (*i >= 0x18) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x180000 + 1), (unsigned int)i[3]+1), i += 4;
11435 else if (*i >= 0x10) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x100000 + 1), (unsigned int)nk__in2(3)+1), i += 5;
11436 else if (*i >= 0x08) nk__lit(i+2, (unsigned int)nk__in2(0) - 0x0800 + 1), i += 2 + (nk__in2(0) - 0x0800 + 1);
11437 else if (*i == 0x07) nk__lit(i+3, (unsigned int)nk__in2(1) + 1), i += 3 + (nk__in2(1) + 1);
11438 else if (*i == 0x06) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), i[4]+1u), i += 5;
11439 else if (*i == 0x04) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), (unsigned int)nk__in2(4)+1u), i += 6;
11440 }
11441 return i;
11442}
11443
11444NK_INTERN unsigned int
11445nk_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
11446{
11447 const unsigned long ADLER_MOD = 65521;
11448 unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
11449 unsigned long blocklen, i;
11450
11451 blocklen = buflen % 5552;
11452 while (buflen) {
11453 for (i=0; i + 7 < blocklen; i += 8) {
11454 s1 += buffer[0]; s2 += s1;
11455 s1 += buffer[1]; s2 += s1;
11456 s1 += buffer[2]; s2 += s1;
11457 s1 += buffer[3]; s2 += s1;
11458 s1 += buffer[4]; s2 += s1;
11459 s1 += buffer[5]; s2 += s1;
11460 s1 += buffer[6]; s2 += s1;
11461 s1 += buffer[7]; s2 += s1;
11462 buffer += 8;
11463 }
11464 for (; i < blocklen; ++i) {
11465 s1 += *buffer++; s2 += s1;
11466 }
11467
11468 s1 %= ADLER_MOD; s2 %= ADLER_MOD;
11469 buflen -= (unsigned int)blocklen;
11470 blocklen = 5552;
11471 }
11472 return (unsigned int)(s2 << 16) + (unsigned int)s1;
11473}
11474
11475NK_INTERN unsigned int
11476nk_decompress(unsigned char *output, unsigned char *i, unsigned int length)
11477{
11478 unsigned int olen;
11479 if (nk__in4(0) != 0x57bC0000) return 0;
11480 if (nk__in4(4) != 0) return 0; /* error! stream is > 4GB */
11481 olen = nk_decompress_length(i);
11482 nk__barrier2 = i;
11483 nk__barrier3 = i+length;
11484 nk__barrier = output + olen;
11485 nk__barrier4 = output;
11486 i += 16;
11487
11488 nk__dout = output;
11489 for (;;) {
11490 unsigned char *old_i = i;
11491 i = nk_decompress_token(i);
11492 if (i == old_i) {
11493 if (*i == 0x05 && i[1] == 0xfa) {
11494 NK_ASSERT(nk__dout == output + olen);
11495 if (nk__dout != output + olen) return 0;
11496 if (nk_adler32(1, output, olen) != (unsigned int) nk__in4(2))
11497 return 0;
11498 return olen;
11499 } else {
11500 NK_ASSERT(0); /* NOTREACHED */
11501 return 0;
11502 }
11503 }
11504 NK_ASSERT(nk__dout <= output + olen);
11505 if (nk__dout > output + olen)
11506 return 0;
11507 }
11508}
11509
11510NK_INTERN unsigned int
11511nk_decode_85_byte(char c)
11512{ return (unsigned int)((c >= '\\') ? c-36 : c-35); }
11513
11514NK_INTERN void
11515nk_decode_85(unsigned char* dst, const unsigned char* src)
11516{
11517 while (*src)
11518 {
11519 unsigned int tmp =
11520 nk_decode_85_byte((char)src[0]) +
11521 85 * (nk_decode_85_byte((char)src[1]) +
11522 85 * (nk_decode_85_byte((char)src[2]) +
11523 85 * (nk_decode_85_byte((char)src[3]) +
11524 85 * nk_decode_85_byte((char)src[4]))));
11525
11526 /* we can't assume little-endianess. */
11527 dst[0] = (unsigned char)((tmp >> 0) & 0xFF);
11528 dst[1] = (unsigned char)((tmp >> 8) & 0xFF);
11529 dst[2] = (unsigned char)((tmp >> 16) & 0xFF);
11530 dst[3] = (unsigned char)((tmp >> 24) & 0xFF);
11531
11532 src += 5;
11533 dst += 4;
11534 }
11535}
11536
11537/* -------------------------------------------------------------
11538 *
11539 * FONT ATLAS
11540 *
11541 * --------------------------------------------------------------*/
11542NK_API struct nk_font_config
11543nk_font_config(float pixel_height)
11544{
11545 struct nk_font_config cfg;
11546 nk_zero_struct(cfg);
11547 cfg.ttf_blob = 0;
11548 cfg.ttf_size = 0;
11549 cfg.ttf_data_owned_by_atlas = 0;
11550 cfg.size = pixel_height;
11551 cfg.oversample_h = 3;
11552 cfg.oversample_v = 1;
11553 cfg.pixel_snap = 0;
11554 cfg.coord_type = NK_COORD_UV;
11555 cfg.spacing = nk_vec2(0,0);
11556 cfg.range = nk_font_default_glyph_ranges();
11557 cfg.merge_mode = 0;
11558 cfg.fallback_glyph = '?';
11559 cfg.font = 0;
11560 return cfg;
11561}
11562
11563#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
11564NK_API void
11565nk_font_atlas_init_default(struct nk_font_atlas *atlas)
11566{
11567 NK_ASSERT(atlas);
11568 if (!atlas) return;
11569 nk_zero_struct(*atlas);
11570 atlas->temporary.userdata.ptr = 0;
11571 atlas->temporary.alloc = nk_malloc;
11572 atlas->temporary.free = nk_mfree;
11573 atlas->permanent.userdata.ptr = 0;
11574 atlas->permanent.alloc = nk_malloc;
11575 atlas->permanent.free = nk_mfree;
11576}
11577#endif
11578
11579NK_API void
11580nk_font_atlas_init(struct nk_font_atlas *atlas, struct nk_allocator *alloc)
11581{
11582 NK_ASSERT(atlas);
11583 NK_ASSERT(alloc);
11584 if (!atlas || !alloc) return;
11585 nk_zero_struct(*atlas);
11586 atlas->permanent = *alloc;
11587 atlas->temporary = *alloc;
11588}
11589
11590NK_API void
11591nk_font_atlas_init_custom(struct nk_font_atlas *atlas,
11592 struct nk_allocator *permanent, struct nk_allocator *temporary)
11593{
11594 NK_ASSERT(atlas);
11595 NK_ASSERT(permanent);
11596 NK_ASSERT(temporary);
11597 if (!atlas || !permanent || !temporary) return;
11598 nk_zero_struct(*atlas);
11599 atlas->permanent = *permanent;
11600 atlas->temporary = *temporary;
11601}
11602
11603NK_API void
11604nk_font_atlas_begin(struct nk_font_atlas *atlas)
11605{
11606 NK_ASSERT(atlas);
11607 NK_ASSERT(atlas->temporary.alloc && atlas->temporary.free);
11608 NK_ASSERT(atlas->permanent.alloc && atlas->permanent.free);
11609 if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free ||
11610 !atlas->temporary.alloc || !atlas->temporary.free) return;
11611 if (atlas->glyphs) {
11612 atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);
11613 atlas->glyphs = 0;
11614 }
11615 if (atlas->pixel) {
11616 atlas->permanent.free(atlas->permanent.userdata, atlas->pixel);
11617 atlas->pixel = 0;
11618 }
11619}
11620
11621NK_API struct nk_font*
11622nk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *config)
11623{
11624 struct nk_font *font = 0;
11625 struct nk_font_config *cfg;
11626
11627 NK_ASSERT(atlas);
11628 NK_ASSERT(atlas->permanent.alloc);
11629 NK_ASSERT(atlas->permanent.free);
11630 NK_ASSERT(atlas->temporary.alloc);
11631 NK_ASSERT(atlas->temporary.free);
11632
11633 NK_ASSERT(config);
11634 NK_ASSERT(config->ttf_blob);
11635 NK_ASSERT(config->ttf_size);
11636 NK_ASSERT(config->size > 0.0f);
11637
11638 if (!atlas || !config || !config->ttf_blob || !config->ttf_size || config->size <= 0.0f||
11639 !atlas->permanent.alloc || !atlas->permanent.free ||
11640 !atlas->temporary.alloc || !atlas->temporary.free)
11641 return 0;
11642
11643 /* allocate and insert font config into list */
11644 cfg = (struct nk_font_config*)
11645 atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config));
11646 NK_MEMCPY(cfg, config, sizeof(*config));
11647 if (!atlas->config) {
11648 atlas->config = cfg;
11649 cfg->next = 0;
11650 } else {
11651 cfg->next = atlas->config;
11652 atlas->config = cfg;
11653 }
11654
11655 /* allocate new font */
11656 if (!config->merge_mode) {
11657 font = (struct nk_font*)
11658 atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font));
11659 NK_ASSERT(font);
11660 if (!font) return 0;
11661 font->config = cfg;
11662 } else {
11663 NK_ASSERT(atlas->font_num);
11664 font = atlas->fonts;
11665 font->config = cfg;
11666 }
11667
11668 /* insert font into list */
11669 if (!config->merge_mode) {
11670 if (!atlas->fonts) {
11671 atlas->fonts = font;
11672 font->next = 0;
11673 } else {
11674 font->next = atlas->fonts;
11675 atlas->fonts = font;
11676 }
11677 cfg->font = &font->info;
11678 }
11679
11680 /* create own copy of .TTF font blob */
11681 if (!config->ttf_data_owned_by_atlas) {
11682 cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size);
11683 NK_ASSERT(cfg->ttf_blob);
11684 if (!cfg->ttf_blob) {
11685 atlas->font_num++;
11686 return 0;
11687 }
11688 NK_MEMCPY(cfg->ttf_blob, config->ttf_blob, cfg->ttf_size);
11689 cfg->ttf_data_owned_by_atlas = 1;
11690 }
11691 atlas->font_num++;
11692 return font;
11693}
11694
11695NK_API struct nk_font*
11696nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory,
11697 nk_size size, float height, const struct nk_font_config *config)
11698{
11699 struct nk_font_config cfg;
11700 NK_ASSERT(memory);
11701 NK_ASSERT(size);
11702
11703 NK_ASSERT(atlas);
11704 NK_ASSERT(atlas->temporary.alloc);
11705 NK_ASSERT(atlas->temporary.free);
11706 NK_ASSERT(atlas->permanent.alloc);
11707 NK_ASSERT(atlas->permanent.free);
11708 if (!atlas || !atlas->temporary.alloc || !atlas->temporary.free || !memory || !size ||
11709 !atlas->permanent.alloc || !atlas->permanent.free)
11710 return 0;
11711
11712 cfg = (config) ? *config: nk_font_config(height);
11713 cfg.ttf_blob = memory;
11714 cfg.ttf_size = size;
11715 cfg.size = height;
11716 cfg.ttf_data_owned_by_atlas = 0;
11717 return nk_font_atlas_add(atlas, &cfg);
11718}
11719
11720#ifdef NK_INCLUDE_STANDARD_IO
11721NK_API struct nk_font*
11722nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path,
11723 float height, const struct nk_font_config *config)
11724{
11725 nk_size size;
11726 char *memory;
11727 struct nk_font_config cfg;
11728
11729 NK_ASSERT(atlas);
11730 NK_ASSERT(atlas->temporary.alloc);
11731 NK_ASSERT(atlas->temporary.free);
11732 NK_ASSERT(atlas->permanent.alloc);
11733 NK_ASSERT(atlas->permanent.free);
11734
11735 if (!atlas || !file_path) return 0;
11736 memory = nk_file_load(file_path, &size, &atlas->permanent);
11737 if (!memory) return 0;
11738
11739 cfg = (config) ? *config: nk_font_config(height);
11740 cfg.ttf_blob = memory;
11741 cfg.ttf_size = size;
11742 cfg.size = height;
11743 cfg.ttf_data_owned_by_atlas = 1;
11744 return nk_font_atlas_add(atlas, &cfg);
11745}
11746#endif
11747
11748NK_API struct nk_font*
11749nk_font_atlas_add_compressed(struct nk_font_atlas *atlas,
11750 void *compressed_data, nk_size compressed_size, float height,
11751 const struct nk_font_config *config)
11752{
11753 unsigned int decompressed_size;
11754 void *decompressed_data;
11755 struct nk_font_config cfg;
11756
11757 NK_ASSERT(atlas);
11758 NK_ASSERT(atlas->temporary.alloc);
11759 NK_ASSERT(atlas->temporary.free);
11760 NK_ASSERT(atlas->permanent.alloc);
11761 NK_ASSERT(atlas->permanent.free);
11762
11763 NK_ASSERT(compressed_data);
11764 NK_ASSERT(compressed_size);
11765 if (!atlas || !compressed_data || !atlas->temporary.alloc || !atlas->temporary.free ||
11766 !atlas->permanent.alloc || !atlas->permanent.free)
11767 return 0;
11768
11769 decompressed_size = nk_decompress_length((unsigned char*)compressed_data);
11770 decompressed_data = atlas->permanent.alloc(atlas->permanent.userdata,0,decompressed_size);
11771 NK_ASSERT(decompressed_data);
11772 if (!decompressed_data) return 0;
11773 nk_decompress((unsigned char*)decompressed_data, (unsigned char*)compressed_data,
11774 (unsigned int)compressed_size);
11775
11776 cfg = (config) ? *config: nk_font_config(height);
11777 cfg.ttf_blob = decompressed_data;
11778 cfg.ttf_size = decompressed_size;
11779 cfg.size = height;
11780 cfg.ttf_data_owned_by_atlas = 1;
11781 return nk_font_atlas_add(atlas, &cfg);
11782}
11783
11784NK_API struct nk_font*
11785nk_font_atlas_add_compressed_base85(struct nk_font_atlas *atlas,
11786 const char *data_base85, float height, const struct nk_font_config *config)
11787{
11788 int compressed_size;
11789 void *compressed_data;
11790 struct nk_font *font;
11791
11792 NK_ASSERT(atlas);
11793 NK_ASSERT(atlas->temporary.alloc);
11794 NK_ASSERT(atlas->temporary.free);
11795 NK_ASSERT(atlas->permanent.alloc);
11796 NK_ASSERT(atlas->permanent.free);
11797
11798 NK_ASSERT(data_base85);
11799 if (!atlas || !data_base85 || !atlas->temporary.alloc || !atlas->temporary.free ||
11800 !atlas->permanent.alloc || !atlas->permanent.free)
11801 return 0;
11802
11803 compressed_size = (((int)nk_strlen(data_base85) + 4) / 5) * 4;
11804 compressed_data = atlas->temporary.alloc(atlas->temporary.userdata,0, (nk_size)compressed_size);
11805 NK_ASSERT(compressed_data);
11806 if (!compressed_data) return 0;
11807 nk_decode_85((unsigned char*)compressed_data, (const unsigned char*)data_base85);
11808 font = nk_font_atlas_add_compressed(atlas, compressed_data,
11809 (nk_size)compressed_size, height, config);
11810 atlas->temporary.free(atlas->temporary.userdata, compressed_data);
11811 return font;
11812}
11813
11814#ifdef NK_INCLUDE_DEFAULT_FONT
11815NK_API struct nk_font*
11816nk_font_atlas_add_default(struct nk_font_atlas *atlas,
11817 float pixel_height, const struct nk_font_config *config)
11818{
11819 NK_ASSERT(atlas);
11820 NK_ASSERT(atlas->temporary.alloc);
11821 NK_ASSERT(atlas->temporary.free);
11822 NK_ASSERT(atlas->permanent.alloc);
11823 NK_ASSERT(atlas->permanent.free);
11824 return nk_font_atlas_add_compressed_base85(atlas,
11825 nk_proggy_clean_ttf_compressed_data_base85, pixel_height, config);
11826}
11827#endif
11828
11829NK_API const void*
11830nk_font_atlas_bake(struct nk_font_atlas *atlas, int *width, int *height,
11831 enum nk_font_atlas_format fmt)
11832{
11833 int i = 0;
11834 void *tmp = 0;
11835 nk_size tmp_size, img_size;
11836 struct nk_font *font_iter;
11837 struct nk_font_baker *baker;
11838
11839 NK_ASSERT(atlas);
11840 NK_ASSERT(atlas->temporary.alloc);
11841 NK_ASSERT(atlas->temporary.free);
11842 NK_ASSERT(atlas->permanent.alloc);
11843 NK_ASSERT(atlas->permanent.free);
11844
11845 NK_ASSERT(width);
11846 NK_ASSERT(height);
11847 if (!atlas || !width || !height ||
11848 !atlas->temporary.alloc || !atlas->temporary.free ||
11849 !atlas->permanent.alloc || !atlas->permanent.free)
11850 return 0;
11851
11852#ifdef NK_INCLUDE_DEFAULT_FONT
11853 /* no font added so just use default font */
11854 if (!atlas->font_num)
11855 atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0);
11856#endif
11857 NK_ASSERT(atlas->font_num);
11858 if (!atlas->font_num) return 0;
11859
11860 /* allocate temporary baker memory required for the baking process */
11861 nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num);
11862 tmp = atlas->temporary.alloc(atlas->temporary.userdata,0, tmp_size);
11863 NK_ASSERT(tmp);
11864 if (!tmp) goto failed;
11865
11866 /* allocate glyph memory for all fonts */
11867 baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary);
11868 atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc(
11869 atlas->permanent.userdata,0, sizeof(struct nk_font_glyph)*(nk_size)atlas->glyph_count);
11870 NK_ASSERT(atlas->glyphs);
11871 if (!atlas->glyphs)
11872 goto failed;
11873
11874 /* pack all glyphs into a tight fit space */
11875 atlas->custom.w = (NK_CURSOR_DATA_W*2)+1;
11876 atlas->custom.h = NK_CURSOR_DATA_H + 1;
11877 if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom,
11878 atlas->config, atlas->font_num, &atlas->temporary))
11879 goto failed;
11880
11881 /* allocate memory for the baked image font atlas */
11882 atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata,0, img_size);
11883 NK_ASSERT(atlas->pixel);
11884 if (!atlas->pixel)
11885 goto failed;
11886
11887 /* bake glyphs and custom white pixel into image */
11888 nk_font_bake(baker, atlas->pixel, *width, *height,
11889 atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num);
11890 nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom,
11891 nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X');
11892
11893 if (fmt == NK_FONT_ATLAS_RGBA32) {
11894 /* convert alpha8 image into rgba32 image */
11895 void *img_rgba = atlas->temporary.alloc(atlas->temporary.userdata,0,
11896 (nk_size)(*width * *height * 4));
11897 NK_ASSERT(img_rgba);
11898 if (!img_rgba) goto failed;
11899 nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel);
11900 atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);
11901 atlas->pixel = img_rgba;
11902 }
11903 atlas->tex_width = *width;
11904 atlas->tex_height = *height;
11905
11906 /* initialize each font */
11907 for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {
11908 struct nk_font *font = font_iter;
11909 struct nk_font_config *config = font->config;
11910 nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs,
11911 config->font, nk_handle_ptr(0));
11912 }
11913
11914 /* initialize each cursor */
11915 {NK_STORAGE const struct nk_vec2 nk_cursor_data[NK_CURSOR_COUNT][3] = {
11916 /* Pos ----- Size ------- Offset --*/
11917 {{ 0, 3}, {12,19}, { 0, 0}},
11918 {{13, 0}, { 7,16}, { 4, 8}},
11919 {{31, 0}, {23,23}, {11,11}},
11920 {{21, 0}, { 9, 23}, { 5,11}},
11921 {{55,18}, {23, 9}, {11, 5}},
11922 {{73, 0}, {17,17}, { 9, 9}},
11923 {{55, 0}, {17,17}, { 9, 9}}
11924 };
11925 for (i = 0; i < NK_CURSOR_COUNT; ++i) {
11926 struct nk_cursor *cursor = &atlas->cursors[i];
11927 cursor->img.w = (unsigned short)*width;
11928 cursor->img.h = (unsigned short)*height;
11929 cursor->img.region[0] = (unsigned short)(atlas->custom.x + nk_cursor_data[i][0].x);
11930 cursor->img.region[1] = (unsigned short)(atlas->custom.y + nk_cursor_data[i][0].y);
11931 cursor->img.region[2] = (unsigned short)nk_cursor_data[i][1].x;
11932 cursor->img.region[3] = (unsigned short)nk_cursor_data[i][1].y;
11933 cursor->size = nk_cursor_data[i][1];
11934 cursor->offset = nk_cursor_data[i][2];
11935 }}
11936 /* free temporary memory */
11937 atlas->temporary.free(atlas->temporary.userdata, tmp);
11938 return atlas->pixel;
11939
11940failed:
11941 /* error so cleanup all memory */
11942 if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp);
11943 if (atlas->glyphs) {
11944 atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);
11945 atlas->glyphs = 0;
11946 }
11947 if (atlas->pixel) {
11948 atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);
11949 atlas->pixel = 0;
11950 }
11951 return 0;
11952}
11953
11954NK_API void
11955nk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture,
11956 struct nk_draw_null_texture *null)
11957{
11958 int i = 0;
11959 struct nk_font *font_iter;
11960 NK_ASSERT(atlas);
11961 if (!atlas) {
11962 if (!null) return;
11963 null->texture = texture;
11964 null->uv = nk_vec2(0.5f,0.5f);
11965 }
11966 if (null) {
11967 null->texture = texture;
11968 null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width;
11969 null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height;
11970 }
11971 for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {
11972 font_iter->texture = texture;
11973#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
11974 font_iter->handle.texture = texture;
11975#endif
11976 }
11977 for (i = 0; i < NK_CURSOR_COUNT; ++i)
11978 atlas->cursors[i].img.handle = texture;
11979
11980 atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);
11981 atlas->pixel = 0;
11982 atlas->tex_width = 0;
11983 atlas->tex_height = 0;
11984 atlas->custom.x = 0;
11985 atlas->custom.y = 0;
11986 atlas->custom.w = 0;
11987 atlas->custom.h = 0;
11988}
11989
11990NK_API void
11991nk_font_atlas_cleanup(struct nk_font_atlas *atlas)
11992{
11993 NK_ASSERT(atlas);
11994 NK_ASSERT(atlas->temporary.alloc);
11995 NK_ASSERT(atlas->temporary.free);
11996 NK_ASSERT(atlas->permanent.alloc);
11997 NK_ASSERT(atlas->permanent.free);
11998
11999 if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;
12000 if (atlas->config) {
12001 struct nk_font_config *iter, *next;
12002 for (iter = atlas->config; iter; iter = next) {
12003 next = iter->next;
12004 atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob);
12005 atlas->permanent.free(atlas->permanent.userdata, iter);
12006 }
12007 }
12008}
12009
12010NK_API void
12011nk_font_atlas_clear(struct nk_font_atlas *atlas)
12012{
12013 NK_ASSERT(atlas);
12014 NK_ASSERT(atlas->temporary.alloc);
12015 NK_ASSERT(atlas->temporary.free);
12016 NK_ASSERT(atlas->permanent.alloc);
12017 NK_ASSERT(atlas->permanent.free);
12018 if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;
12019
12020 nk_font_atlas_cleanup(atlas);
12021 if (atlas->fonts) {
12022 struct nk_font *iter, *next;
12023 for (iter = atlas->fonts; iter; iter = next) {
12024 next = iter->next;
12025 atlas->permanent.free(atlas->permanent.userdata, iter);
12026 }
12027 atlas->fonts = 0;
12028 }
12029 if (atlas->glyphs)
12030 atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);
12031 nk_zero_struct(*atlas);
12032}
12033#endif
12034/* ==============================================================
12035 *
12036 * INPUT
12037 *
12038 * ===============================================================*/
12039NK_API void
12040nk_input_begin(struct nk_context *ctx)
12041{
12042 int i;
12043 struct nk_input *in;
12044 NK_ASSERT(ctx);
12045 if (!ctx) return;
12046 in = &ctx->input;
12047 for (i = 0; i < NK_BUTTON_MAX; ++i)
12048 in->mouse.buttons[i].clicked = 0;
12049
12050 in->keyboard.text_len = 0;
12051 in->mouse.scroll_delta = nk_vec2(0,0);
12052 in->mouse.prev.x = in->mouse.pos.x;
12053 in->mouse.prev.y = in->mouse.pos.y;
12054 in->mouse.delta.x = 0;
12055 in->mouse.delta.y = 0;
12056 for (i = 0; i < NK_KEY_MAX; i++)
12057 in->keyboard.keys[i].clicked = 0;
12058}
12059
12060NK_API void
12061nk_input_end(struct nk_context *ctx)
12062{
12063 struct nk_input *in;
12064 NK_ASSERT(ctx);
12065 if (!ctx) return;
12066 in = &ctx->input;
12067 if (in->mouse.grab)
12068 in->mouse.grab = 0;
12069 if (in->mouse.ungrab) {
12070 in->mouse.grabbed = 0;
12071 in->mouse.ungrab = 0;
12072 in->mouse.grab = 0;
12073 }
12074}
12075
12076NK_API void
12077nk_input_motion(struct nk_context *ctx, int x, int y)
12078{
12079 struct nk_input *in;
12080 NK_ASSERT(ctx);
12081 if (!ctx) return;
12082 in = &ctx->input;
12083 in->mouse.pos.x = (float)x;
12084 in->mouse.pos.y = (float)y;
12085 in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x;
12086 in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y;
12087}
12088
12089NK_API void
12090nk_input_key(struct nk_context *ctx, enum nk_keys key, int down)
12091{
12092 struct nk_input *in;
12093 NK_ASSERT(ctx);
12094 if (!ctx) return;
12095 in = &ctx->input;
12096 in->keyboard.keys[key].down = down;
12097 in->keyboard.keys[key].clicked++;
12098}
12099
12100NK_API void
12101nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, int down)
12102{
12103 struct nk_mouse_button *btn;
12104 struct nk_input *in;
12105 NK_ASSERT(ctx);
12106 if (!ctx) return;
12107 in = &ctx->input;
12108 if (in->mouse.buttons[id].down == down) return;
12109
12110 btn = &in->mouse.buttons[id];
12111 btn->clicked_pos.x = (float)x;
12112 btn->clicked_pos.y = (float)y;
12113 btn->down = down;
12114 btn->clicked++;
12115}
12116
12117NK_API void
12118nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val)
12119{
12120 NK_ASSERT(ctx);
12121 if (!ctx) return;
12122 ctx->input.mouse.scroll_delta.x += val.x;
12123 ctx->input.mouse.scroll_delta.y += val.y;
12124}
12125
12126NK_API void
12127nk_input_glyph(struct nk_context *ctx, const nk_glyph glyph)
12128{
12129 int len = 0;
12130 nk_rune unicode;
12131 struct nk_input *in;
12132
12133 NK_ASSERT(ctx);
12134 if (!ctx) return;
12135 in = &ctx->input;
12136
12137 len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE);
12138 if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) {
12139 nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len],
12140 NK_INPUT_MAX - in->keyboard.text_len);
12141 in->keyboard.text_len += len;
12142 }
12143}
12144
12145NK_API void
12146nk_input_char(struct nk_context *ctx, char c)
12147{
12148 nk_glyph glyph;
12149 NK_ASSERT(ctx);
12150 if (!ctx) return;
12151 glyph[0] = c;
12152 nk_input_glyph(ctx, glyph);
12153}
12154
12155NK_API void
12156nk_input_unicode(struct nk_context *ctx, nk_rune unicode)
12157{
12158 nk_glyph rune;
12159 NK_ASSERT(ctx);
12160 if (!ctx) return;
12161 nk_utf_encode(unicode, rune, NK_UTF_SIZE);
12162 nk_input_glyph(ctx, rune);
12163}
12164
12165NK_API int
12166nk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id)
12167{
12168 const struct nk_mouse_button *btn;
12169 if (!i) return nk_false;
12170 btn = &i->mouse.buttons[id];
12171 return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false;
12172}
12173
12174NK_API int
12175nk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,
12176 struct nk_rect b)
12177{
12178 const struct nk_mouse_button *btn;
12179 if (!i) return nk_false;
12180 btn = &i->mouse.buttons[id];
12181 if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))
12182 return nk_false;
12183 return nk_true;
12184}
12185
12186NK_API int
12187nk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
12188 struct nk_rect b, int down)
12189{
12190 const struct nk_mouse_button *btn;
12191 if (!i) return nk_false;
12192 btn = &i->mouse.buttons[id];
12193 return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down);
12194}
12195
12196NK_API int
12197nk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,
12198 struct nk_rect b)
12199{
12200 const struct nk_mouse_button *btn;
12201 if (!i) return nk_false;
12202 btn = &i->mouse.buttons[id];
12203 return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) &&
12204 btn->clicked) ? nk_true : nk_false;
12205}
12206
12207NK_API int
12208nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
12209 struct nk_rect b, int down)
12210{
12211 const struct nk_mouse_button *btn;
12212 if (!i) return nk_false;
12213 btn = &i->mouse.buttons[id];
12214 return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) &&
12215 btn->clicked) ? nk_true : nk_false;
12216}
12217
12218NK_API int
12219nk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b)
12220{
12221 int i, down = 0;
12222 for (i = 0; i < NK_BUTTON_MAX; ++i)
12223 down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b);
12224 return down;
12225}
12226
12227NK_API int
12228nk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect)
12229{
12230 if (!i) return nk_false;
12231 return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h);
12232}
12233
12234NK_API int
12235nk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect)
12236{
12237 if (!i) return nk_false;
12238 return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h);
12239}
12240
12241NK_API int
12242nk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect)
12243{
12244 if (!i) return nk_false;
12245 if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false;
12246 return nk_input_is_mouse_click_in_rect(i, id, rect);
12247}
12248
12249NK_API int
12250nk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id)
12251{
12252 if (!i) return nk_false;
12253 return i->mouse.buttons[id].down;
12254}
12255
12256NK_API int
12257nk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id)
12258{
12259 const struct nk_mouse_button *b;
12260 if (!i) return nk_false;
12261 b = &i->mouse.buttons[id];
12262 if (b->down && b->clicked)
12263 return nk_true;
12264 return nk_false;
12265}
12266
12267NK_API int
12268nk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id)
12269{
12270 if (!i) return nk_false;
12271 return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked);
12272}
12273
12274NK_API int
12275nk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key)
12276{
12277 const struct nk_key *k;
12278 if (!i) return nk_false;
12279 k = &i->keyboard.keys[key];
12280 if ((k->down && k->clicked) || (!k->down && k->clicked >= 2))
12281 return nk_true;
12282 return nk_false;
12283}
12284
12285NK_API int
12286nk_input_is_key_released(const struct nk_input *i, enum nk_keys key)
12287{
12288 const struct nk_key *k;
12289 if (!i) return nk_false;
12290 k = &i->keyboard.keys[key];
12291 if ((!k->down && k->clicked) || (k->down && k->clicked >= 2))
12292 return nk_true;
12293 return nk_false;
12294}
12295
12296NK_API int
12297nk_input_is_key_down(const struct nk_input *i, enum nk_keys key)
12298{
12299 const struct nk_key *k;
12300 if (!i) return nk_false;
12301 k = &i->keyboard.keys[key];
12302 if (k->down) return nk_true;
12303 return nk_false;
12304}
12305
12306/*
12307 * ==============================================================
12308 *
12309 * TEXT EDITOR
12310 *
12311 * ===============================================================
12312 */
12313/* stb_textedit.h - v1.8 - public domain - Sean Barrett */
12314struct nk_text_find {
12315 float x,y; /* position of n'th character */
12316 float height; /* height of line */
12317 int first_char, length; /* first char of row, and length */
12318 int prev_first; /*_ first char of previous row */
12319};
12320
12321struct nk_text_edit_row {
12322 float x0,x1;
12323 /* starting x location, end x location (allows for align=right, etc) */
12324 float baseline_y_delta;
12325 /* position of baseline relative to previous row's baseline*/
12326 float ymin,ymax;
12327 /* height of row above and below baseline */
12328 int num_chars;
12329};
12330
12331/* forward declarations */
12332NK_INTERN void nk_textedit_makeundo_delete(struct nk_text_edit*, int, int);
12333NK_INTERN void nk_textedit_makeundo_insert(struct nk_text_edit*, int, int);
12334NK_INTERN void nk_textedit_makeundo_replace(struct nk_text_edit*, int, int, int);
12335#define NK_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
12336
12337NK_INTERN float
12338nk_textedit_get_width(const struct nk_text_edit *edit, int line_start, int char_id,
12339 const struct nk_user_font *font)
12340{
12341 int len = 0;
12342 nk_rune unicode = 0;
12343 const char *str = nk_str_at_const(&edit->string, line_start + char_id, &unicode, &len);
12344 return font->width(font->userdata, font->height, str, len);
12345}
12346
12347NK_INTERN void
12348nk_textedit_layout_row(struct nk_text_edit_row *r, struct nk_text_edit *edit,
12349 int line_start_id, float row_height, const struct nk_user_font *font)
12350{
12351 int l;
12352 int glyphs = 0;
12353 nk_rune unicode;
12354 const char *remaining;
12355 int len = nk_str_len_char(&edit->string);
12356 const char *end = nk_str_get_const(&edit->string) + len;
12357 const char *text = nk_str_at_const(&edit->string, line_start_id, &unicode, &l);
12358 const struct nk_vec2 size = nk_text_calculate_text_bounds(font,
12359 text, (int)(end - text), row_height, &remaining, 0, &glyphs, NK_STOP_ON_NEW_LINE);
12360
12361 r->x0 = 0.0f;
12362 r->x1 = size.x;
12363 r->baseline_y_delta = size.y;
12364 r->ymin = 0.0f;
12365 r->ymax = size.y;
12366 r->num_chars = glyphs;
12367}
12368
12369NK_INTERN int
12370nk_textedit_locate_coord(struct nk_text_edit *edit, float x, float y,
12371 const struct nk_user_font *font, float row_height)
12372{
12373 struct nk_text_edit_row r;
12374 int n = edit->string.len;
12375 float base_y = 0, prev_x;
12376 int i=0, k;
12377
12378 r.x0 = r.x1 = 0;
12379 r.ymin = r.ymax = 0;
12380 r.num_chars = 0;
12381
12382 /* search rows to find one that straddles 'y' */
12383 while (i < n) {
12384 nk_textedit_layout_row(&r, edit, i, row_height, font);
12385 if (r.num_chars <= 0)
12386 return n;
12387
12388 if (i==0 && y < base_y + r.ymin)
12389 return 0;
12390
12391 if (y < base_y + r.ymax)
12392 break;
12393
12394 i += r.num_chars;
12395 base_y += r.baseline_y_delta;
12396 }
12397
12398 /* below all text, return 'after' last character */
12399 if (i >= n)
12400 return n;
12401
12402 /* check if it's before the beginning of the line */
12403 if (x < r.x0)
12404 return i;
12405
12406 /* check if it's before the end of the line */
12407 if (x < r.x1) {
12408 /* search characters in row for one that straddles 'x' */
12409 k = i;
12410 prev_x = r.x0;
12411 for (i=0; i < r.num_chars; ++i) {
12412 float w = nk_textedit_get_width(edit, k, i, font);
12413 if (x < prev_x+w) {
12414 if (x < prev_x+w/2)
12415 return k+i;
12416 else return k+i+1;
12417 }
12418 prev_x += w;
12419 }
12420 /* shouldn't happen, but if it does, fall through to end-of-line case */
12421 }
12422
12423 /* if the last character is a newline, return that.
12424 * otherwise return 'after' the last character */
12425 if (nk_str_rune_at(&edit->string, i+r.num_chars-1) == '\n')
12426 return i+r.num_chars-1;
12427 else return i+r.num_chars;
12428}
12429
12430NK_INTERN void
12431nk_textedit_click(struct nk_text_edit *state, float x, float y,
12432 const struct nk_user_font *font, float row_height)
12433{
12434 /* API click: on mouse down, move the cursor to the clicked location,
12435 * and reset the selection */
12436 state->cursor = nk_textedit_locate_coord(state, x, y, font, row_height);
12437 state->select_start = state->cursor;
12438 state->select_end = state->cursor;
12439 state->has_preferred_x = 0;
12440}
12441
12442NK_INTERN void
12443nk_textedit_drag(struct nk_text_edit *state, float x, float y,
12444 const struct nk_user_font *font, float row_height)
12445{
12446 /* API drag: on mouse drag, move the cursor and selection endpoint
12447 * to the clicked location */
12448 int p = nk_textedit_locate_coord(state, x, y, font, row_height);
12449 if (state->select_start == state->select_end)
12450 state->select_start = state->cursor;
12451 state->cursor = state->select_end = p;
12452}
12453
12454NK_INTERN void
12455nk_textedit_find_charpos(struct nk_text_find *find, struct nk_text_edit *state,
12456 int n, int single_line, const struct nk_user_font *font, float row_height)
12457{
12458 /* find the x/y location of a character, and remember info about the previous
12459 * row in case we get a move-up event (for page up, we'll have to rescan) */
12460 struct nk_text_edit_row r;
12461 int prev_start = 0;
12462 int z = state->string.len;
12463 int i=0, first;
12464
12465 nk_zero_struct(r);
12466 if (n == z) {
12467 /* if it's at the end, then find the last line -- simpler than trying to
12468 explicitly handle this case in the regular code */
12469 nk_textedit_layout_row(&r, state, 0, row_height, font);
12470 if (single_line) {
12471 find->first_char = 0;
12472 find->length = z;
12473 } else {
12474 while (i < z) {
12475 prev_start = i;
12476 i += r.num_chars;
12477 nk_textedit_layout_row(&r, state, i, row_height, font);
12478 }
12479
12480 find->first_char = i;
12481 find->length = r.num_chars;
12482 }
12483 find->x = r.x1;
12484 find->y = r.ymin;
12485 find->height = r.ymax - r.ymin;
12486 find->prev_first = prev_start;
12487 return;
12488 }
12489
12490 /* search rows to find the one that straddles character n */
12491 find->y = 0;
12492
12493 for(;;) {
12494 nk_textedit_layout_row(&r, state, i, row_height, font);
12495 if (n < i + r.num_chars) break;
12496 prev_start = i;
12497 i += r.num_chars;
12498 find->y += r.baseline_y_delta;
12499 }
12500
12501 find->first_char = first = i;
12502 find->length = r.num_chars;
12503 find->height = r.ymax - r.ymin;
12504 find->prev_first = prev_start;
12505
12506 /* now scan to find xpos */
12507 find->x = r.x0;
12508 for (i=0; first+i < n; ++i)
12509 find->x += nk_textedit_get_width(state, first, i, font);
12510}
12511
12512NK_INTERN void
12513nk_textedit_clamp(struct nk_text_edit *state)
12514{
12515 /* make the selection/cursor state valid if client altered the string */
12516 int n = state->string.len;
12517 if (NK_TEXT_HAS_SELECTION(state)) {
12518 if (state->select_start > n) state->select_start = n;
12519 if (state->select_end > n) state->select_end = n;
12520 /* if clamping forced them to be equal, move the cursor to match */
12521 if (state->select_start == state->select_end)
12522 state->cursor = state->select_start;
12523 }
12524 if (state->cursor > n) state->cursor = n;
12525}
12526
12527NK_API void
12528nk_textedit_delete(struct nk_text_edit *state, int where, int len)
12529{
12530 /* delete characters while updating undo */
12531 nk_textedit_makeundo_delete(state, where, len);
12532 nk_str_delete_runes(&state->string, where, len);
12533 state->has_preferred_x = 0;
12534}
12535
12536NK_API void
12537nk_textedit_delete_selection(struct nk_text_edit *state)
12538{
12539 /* delete the section */
12540 nk_textedit_clamp(state);
12541 if (NK_TEXT_HAS_SELECTION(state)) {
12542 if (state->select_start < state->select_end) {
12543 nk_textedit_delete(state, state->select_start,
12544 state->select_end - state->select_start);
12545 state->select_end = state->cursor = state->select_start;
12546 } else {
12547 nk_textedit_delete(state, state->select_end,
12548 state->select_start - state->select_end);
12549 state->select_start = state->cursor = state->select_end;
12550 }
12551 state->has_preferred_x = 0;
12552 }
12553}
12554
12555NK_INTERN void
12556nk_textedit_sortselection(struct nk_text_edit *state)
12557{
12558 /* canonicalize the selection so start <= end */
12559 if (state->select_end < state->select_start) {
12560 int temp = state->select_end;
12561 state->select_end = state->select_start;
12562 state->select_start = temp;
12563 }
12564}
12565
12566NK_INTERN void
12567nk_textedit_move_to_first(struct nk_text_edit *state)
12568{
12569 /* move cursor to first character of selection */
12570 if (NK_TEXT_HAS_SELECTION(state)) {
12571 nk_textedit_sortselection(state);
12572 state->cursor = state->select_start;
12573 state->select_end = state->select_start;
12574 state->has_preferred_x = 0;
12575 }
12576}
12577
12578NK_INTERN void
12579nk_textedit_move_to_last(struct nk_text_edit *state)
12580{
12581 /* move cursor to last character of selection */
12582 if (NK_TEXT_HAS_SELECTION(state)) {
12583 nk_textedit_sortselection(state);
12584 nk_textedit_clamp(state);
12585 state->cursor = state->select_end;
12586 state->select_start = state->select_end;
12587 state->has_preferred_x = 0;
12588 }
12589}
12590
12591NK_INTERN int
12592nk_is_word_boundary( struct nk_text_edit *state, int idx)
12593{
12594 int len;
12595 nk_rune c;
12596 if (idx <= 0) return 1;
12597 if (!nk_str_at_rune(&state->string, idx, &c, &len)) return 1;
12598 return (c == ' ' || c == '\t' ||c == 0x3000 || c == ',' || c == ';' ||
12599 c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' ||
12600 c == '|');
12601}
12602
12603NK_INTERN int
12604nk_textedit_move_to_word_previous(struct nk_text_edit *state)
12605{
12606 int c = state->cursor - 1;
12607 while( c >= 0 && !nk_is_word_boundary(state, c))
12608 --c;
12609
12610 if( c < 0 )
12611 c = 0;
12612
12613 return c;
12614}
12615
12616NK_INTERN int
12617nk_textedit_move_to_word_next(struct nk_text_edit *state)
12618{
12619 const int len = state->string.len;
12620 int c = state->cursor+1;
12621 while( c < len && !nk_is_word_boundary(state, c))
12622 ++c;
12623
12624 if( c > len )
12625 c = len;
12626
12627 return c;
12628}
12629
12630NK_INTERN void
12631nk_textedit_prep_selection_at_cursor(struct nk_text_edit *state)
12632{
12633 /* update selection and cursor to match each other */
12634 if (!NK_TEXT_HAS_SELECTION(state))
12635 state->select_start = state->select_end = state->cursor;
12636 else state->cursor = state->select_end;
12637}
12638
12639NK_API int
12640nk_textedit_cut(struct nk_text_edit *state)
12641{
12642 /* API cut: delete selection */
12643 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
12644 return 0;
12645 if (NK_TEXT_HAS_SELECTION(state)) {
12646 nk_textedit_delete_selection(state); /* implicitly clamps */
12647 state->has_preferred_x = 0;
12648 return 1;
12649 }
12650 return 0;
12651}
12652
12653NK_API int
12654nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len)
12655{
12656 /* API paste: replace existing selection with passed-in text */
12657 int glyphs;
12658 const char *text = (const char *) ctext;
12659 if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0;
12660
12661 /* if there's a selection, the paste should delete it */
12662 nk_textedit_clamp(state);
12663 nk_textedit_delete_selection(state);
12664
12665 /* try to insert the characters */
12666 glyphs = nk_utf_len(ctext, len);
12667 if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) {
12668 nk_textedit_makeundo_insert(state, state->cursor, glyphs);
12669 state->cursor += len;
12670 state->has_preferred_x = 0;
12671 return 1;
12672 }
12673 /* remove the undo since we didn't actually insert the characters */
12674 if (state->undo.undo_point)
12675 --state->undo.undo_point;
12676 return 0;
12677}
12678
12679NK_API void
12680nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len)
12681{
12682 nk_rune unicode;
12683 int glyph_len;
12684 int text_len = 0;
12685
12686 NK_ASSERT(state);
12687 NK_ASSERT(text);
12688 if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return;
12689
12690 glyph_len = nk_utf_decode(text, &unicode, total_len);
12691 while ((text_len < total_len) && glyph_len)
12692 {
12693 /* don't insert a backward delete, just process the event */
12694 if (unicode == 127) goto next;
12695 /* can't add newline in single-line mode */
12696 if (unicode == '\n' && state->single_line) goto next;
12697 /* filter incoming text */
12698 if (state->filter && !state->filter(state, unicode)) goto next;
12699
12700 if (!NK_TEXT_HAS_SELECTION(state) &&
12701 state->cursor < state->string.len)
12702 {
12703 if (state->mode == NK_TEXT_EDIT_MODE_REPLACE) {
12704 nk_textedit_makeundo_replace(state, state->cursor, 1, 1);
12705 nk_str_delete_runes(&state->string, state->cursor, 1);
12706 }
12707 if (nk_str_insert_text_utf8(&state->string, state->cursor,
12708 text+text_len, 1))
12709 {
12710 ++state->cursor;
12711 state->has_preferred_x = 0;
12712 }
12713 } else {
12714 nk_textedit_delete_selection(state); /* implicitly clamps */
12715 if (nk_str_insert_text_utf8(&state->string, state->cursor,
12716 text+text_len, 1))
12717 {
12718 nk_textedit_makeundo_insert(state, state->cursor, 1);
12719 ++state->cursor;
12720 state->has_preferred_x = 0;
12721 }
12722 }
12723 next:
12724 text_len += glyph_len;
12725 glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len);
12726 }
12727}
12728
12729NK_INTERN void
12730nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod,
12731 const struct nk_user_font *font, float row_height)
12732{
12733retry:
12734 switch (key)
12735 {
12736 case NK_KEY_NONE:
12737 case NK_KEY_CTRL:
12738 case NK_KEY_ENTER:
12739 case NK_KEY_SHIFT:
12740 case NK_KEY_TAB:
12741 case NK_KEY_COPY:
12742 case NK_KEY_CUT:
12743 case NK_KEY_PASTE:
12744 case NK_KEY_MAX:
12745 default: break;
12746 case NK_KEY_TEXT_UNDO:
12747 nk_textedit_undo(state);
12748 state->has_preferred_x = 0;
12749 break;
12750
12751 case NK_KEY_TEXT_REDO:
12752 nk_textedit_redo(state);
12753 state->has_preferred_x = 0;
12754 break;
12755
12756 case NK_KEY_TEXT_SELECT_ALL:
12757 nk_textedit_select_all(state);
12758 state->has_preferred_x = 0;
12759 break;
12760
12761 case NK_KEY_TEXT_INSERT_MODE:
12762 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
12763 state->mode = NK_TEXT_EDIT_MODE_INSERT;
12764 break;
12765 case NK_KEY_TEXT_REPLACE_MODE:
12766 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
12767 state->mode = NK_TEXT_EDIT_MODE_REPLACE;
12768 break;
12769 case NK_KEY_TEXT_RESET_MODE:
12770 if (state->mode == NK_TEXT_EDIT_MODE_INSERT ||
12771 state->mode == NK_TEXT_EDIT_MODE_REPLACE)
12772 state->mode = NK_TEXT_EDIT_MODE_VIEW;
12773 break;
12774
12775 case NK_KEY_LEFT:
12776 if (shift_mod) {
12777 nk_textedit_clamp(state);
12778 nk_textedit_prep_selection_at_cursor(state);
12779 /* move selection left */
12780 if (state->select_end > 0)
12781 --state->select_end;
12782 state->cursor = state->select_end;
12783 state->has_preferred_x = 0;
12784 } else {
12785 /* if currently there's a selection,
12786 * move cursor to start of selection */
12787 if (NK_TEXT_HAS_SELECTION(state))
12788 nk_textedit_move_to_first(state);
12789 else if (state->cursor > 0)
12790 --state->cursor;
12791 state->has_preferred_x = 0;
12792 } break;
12793
12794 case NK_KEY_RIGHT:
12795 if (shift_mod) {
12796 nk_textedit_prep_selection_at_cursor(state);
12797 /* move selection right */
12798 ++state->select_end;
12799 nk_textedit_clamp(state);
12800 state->cursor = state->select_end;
12801 state->has_preferred_x = 0;
12802 } else {
12803 /* if currently there's a selection,
12804 * move cursor to end of selection */
12805 if (NK_TEXT_HAS_SELECTION(state))
12806 nk_textedit_move_to_last(state);
12807 else ++state->cursor;
12808 nk_textedit_clamp(state);
12809 state->has_preferred_x = 0;
12810 } break;
12811
12812 case NK_KEY_TEXT_WORD_LEFT:
12813 if (shift_mod) {
12814 if( !NK_TEXT_HAS_SELECTION( state ) )
12815 nk_textedit_prep_selection_at_cursor(state);
12816 state->cursor = nk_textedit_move_to_word_previous(state);
12817 state->select_end = state->cursor;
12818 nk_textedit_clamp(state );
12819 } else {
12820 if (NK_TEXT_HAS_SELECTION(state))
12821 nk_textedit_move_to_first(state);
12822 else {
12823 state->cursor = nk_textedit_move_to_word_previous(state);
12824 nk_textedit_clamp(state );
12825 }
12826 } break;
12827
12828 case NK_KEY_TEXT_WORD_RIGHT:
12829 if (shift_mod) {
12830 if( !NK_TEXT_HAS_SELECTION( state ) )
12831 nk_textedit_prep_selection_at_cursor(state);
12832 state->cursor = nk_textedit_move_to_word_next(state);
12833 state->select_end = state->cursor;
12834 nk_textedit_clamp(state);
12835 } else {
12836 if (NK_TEXT_HAS_SELECTION(state))
12837 nk_textedit_move_to_last(state);
12838 else {
12839 state->cursor = nk_textedit_move_to_word_next(state);
12840 nk_textedit_clamp(state );
12841 }
12842 } break;
12843
12844 case NK_KEY_DOWN: {
12845 struct nk_text_find find;
12846 struct nk_text_edit_row row;
12847 int i, sel = shift_mod;
12848
12849 if (state->single_line) {
12850 /* on windows, up&down in single-line behave like left&right */
12851 key = NK_KEY_RIGHT;
12852 goto retry;
12853 }
12854
12855 if (sel)
12856 nk_textedit_prep_selection_at_cursor(state);
12857 else if (NK_TEXT_HAS_SELECTION(state))
12858 nk_textedit_move_to_last(state);
12859
12860 /* compute current position of cursor point */
12861 nk_textedit_clamp(state);
12862 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
12863 font, row_height);
12864
12865 /* now find character position down a row */
12866 if (find.length)
12867 {
12868 float x;
12869 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
12870 int start = find.first_char + find.length;
12871
12872 state->cursor = start;
12873 nk_textedit_layout_row(&row, state, state->cursor, row_height, font);
12874 x = row.x0;
12875
12876 for (i=0; i < row.num_chars && x < row.x1; ++i) {
12877 float dx = nk_textedit_get_width(state, start, i, font);
12878 x += dx;
12879 if (x > goal_x)
12880 break;
12881 ++state->cursor;
12882 }
12883 nk_textedit_clamp(state);
12884
12885 state->has_preferred_x = 1;
12886 state->preferred_x = goal_x;
12887 if (sel)
12888 state->select_end = state->cursor;
12889 }
12890 } break;
12891
12892 case NK_KEY_UP: {
12893 struct nk_text_find find;
12894 struct nk_text_edit_row row;
12895 int i, sel = shift_mod;
12896
12897 if (state->single_line) {
12898 /* on windows, up&down become left&right */
12899 key = NK_KEY_LEFT;
12900 goto retry;
12901 }
12902
12903 if (sel)
12904 nk_textedit_prep_selection_at_cursor(state);
12905 else if (NK_TEXT_HAS_SELECTION(state))
12906 nk_textedit_move_to_first(state);
12907
12908 /* compute current position of cursor point */
12909 nk_textedit_clamp(state);
12910 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
12911 font, row_height);
12912
12913 /* can only go up if there's a previous row */
12914 if (find.prev_first != find.first_char) {
12915 /* now find character position up a row */
12916 float x;
12917 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
12918
12919 state->cursor = find.prev_first;
12920 nk_textedit_layout_row(&row, state, state->cursor, row_height, font);
12921 x = row.x0;
12922
12923 for (i=0; i < row.num_chars && x < row.x1; ++i) {
12924 float dx = nk_textedit_get_width(state, find.prev_first, i, font);
12925 x += dx;
12926 if (x > goal_x)
12927 break;
12928 ++state->cursor;
12929 }
12930 nk_textedit_clamp(state);
12931
12932 state->has_preferred_x = 1;
12933 state->preferred_x = goal_x;
12934 if (sel) state->select_end = state->cursor;
12935 }
12936 } break;
12937
12938 case NK_KEY_DEL:
12939 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
12940 break;
12941 if (NK_TEXT_HAS_SELECTION(state))
12942 nk_textedit_delete_selection(state);
12943 else {
12944 int n = state->string.len;
12945 if (state->cursor < n)
12946 nk_textedit_delete(state, state->cursor, 1);
12947 }
12948 state->has_preferred_x = 0;
12949 break;
12950
12951 case NK_KEY_BACKSPACE:
12952 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
12953 break;
12954 if (NK_TEXT_HAS_SELECTION(state))
12955 nk_textedit_delete_selection(state);
12956 else {
12957 nk_textedit_clamp(state);
12958 if (state->cursor > 0) {
12959 nk_textedit_delete(state, state->cursor-1, 1);
12960 --state->cursor;
12961 }
12962 }
12963 state->has_preferred_x = 0;
12964 break;
12965
12966 case NK_KEY_TEXT_START:
12967 if (shift_mod) {
12968 nk_textedit_prep_selection_at_cursor(state);
12969 state->cursor = state->select_end = 0;
12970 state->has_preferred_x = 0;
12971 } else {
12972 state->cursor = state->select_start = state->select_end = 0;
12973 state->has_preferred_x = 0;
12974 }
12975 break;
12976
12977 case NK_KEY_TEXT_END:
12978 if (shift_mod) {
12979 nk_textedit_prep_selection_at_cursor(state);
12980 state->cursor = state->select_end = state->string.len;
12981 state->has_preferred_x = 0;
12982 } else {
12983 state->cursor = state->string.len;
12984 state->select_start = state->select_end = 0;
12985 state->has_preferred_x = 0;
12986 }
12987 break;
12988
12989 case NK_KEY_TEXT_LINE_START: {
12990 if (shift_mod) {
12991 struct nk_text_find find;
12992 nk_textedit_clamp(state);
12993 nk_textedit_prep_selection_at_cursor(state);
12994 if (state->string.len && state->cursor == state->string.len)
12995 --state->cursor;
12996 nk_textedit_find_charpos(&find, state,state->cursor, state->single_line,
12997 font, row_height);
12998 state->cursor = state->select_end = find.first_char;
12999 state->has_preferred_x = 0;
13000 } else {
13001 struct nk_text_find find;
13002 if (state->string.len && state->cursor == state->string.len)
13003 --state->cursor;
13004 nk_textedit_clamp(state);
13005 nk_textedit_move_to_first(state);
13006 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
13007 font, row_height);
13008 state->cursor = find.first_char;
13009 state->has_preferred_x = 0;
13010 }
13011 } break;
13012
13013 case NK_KEY_TEXT_LINE_END: {
13014 if (shift_mod) {
13015 struct nk_text_find find;
13016 nk_textedit_clamp(state);
13017 nk_textedit_prep_selection_at_cursor(state);
13018 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
13019 font, row_height);
13020 state->has_preferred_x = 0;
13021 state->cursor = find.first_char + find.length;
13022 if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n')
13023 --state->cursor;
13024 state->select_end = state->cursor;
13025 } else {
13026 struct nk_text_find find;
13027 nk_textedit_clamp(state);
13028 nk_textedit_move_to_first(state);
13029 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
13030 font, row_height);
13031
13032 state->has_preferred_x = 0;
13033 state->cursor = find.first_char + find.length;
13034 if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n')
13035 --state->cursor;
13036 }} break;
13037 }
13038}
13039
13040NK_INTERN void
13041nk_textedit_flush_redo(struct nk_text_undo_state *state)
13042{
13043 state->redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;
13044 state->redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;
13045}
13046
13047NK_INTERN void
13048nk_textedit_discard_undo(struct nk_text_undo_state *state)
13049{
13050 /* discard the oldest entry in the undo list */
13051 if (state->undo_point > 0) {
13052 /* if the 0th undo state has characters, clean those up */
13053 if (state->undo_rec[0].char_storage >= 0) {
13054 int n = state->undo_rec[0].insert_length, i;
13055 /* delete n characters from all other records */
13056 state->undo_char_point = (short)(state->undo_char_point - n);
13057 NK_MEMCPY(state->undo_char, state->undo_char + n,
13058 (nk_size)state->undo_char_point*sizeof(nk_rune));
13059 for (i=0; i < state->undo_point; ++i) {
13060 if (state->undo_rec[i].char_storage >= 0)
13061 state->undo_rec[i].char_storage = (short)
13062 (state->undo_rec[i].char_storage - n);
13063 }
13064 }
13065 --state->undo_point;
13066 NK_MEMCPY(state->undo_rec, state->undo_rec+1,
13067 (nk_size)((nk_size)state->undo_point * sizeof(state->undo_rec[0])));
13068 }
13069}
13070
13071NK_INTERN void
13072nk_textedit_discard_redo(struct nk_text_undo_state *state)
13073{
13074/* discard the oldest entry in the redo list--it's bad if this
13075 ever happens, but because undo & redo have to store the actual
13076 characters in different cases, the redo character buffer can
13077 fill up even though the undo buffer didn't */
13078 nk_size num;
13079 int k = NK_TEXTEDIT_UNDOSTATECOUNT-1;
13080 if (state->redo_point <= k) {
13081 /* if the k'th undo state has characters, clean those up */
13082 if (state->undo_rec[k].char_storage >= 0) {
13083 int n = state->undo_rec[k].insert_length, i;
13084 /* delete n characters from all other records */
13085 state->redo_char_point = (short)(state->redo_char_point + n);
13086 num = (nk_size)(NK_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point);
13087 NK_MEMCPY(state->undo_char + state->redo_char_point,
13088 state->undo_char + state->redo_char_point-n, num * sizeof(char));
13089 for (i = state->redo_point; i < k; ++i) {
13090 if (state->undo_rec[i].char_storage >= 0) {
13091 state->undo_rec[i].char_storage = (short)
13092 (state->undo_rec[i].char_storage + n);
13093 }
13094 }
13095 }
13096 ++state->redo_point;
13097 num = (nk_size)(NK_TEXTEDIT_UNDOSTATECOUNT - state->redo_point);
13098 if (num) NK_MEMCPY(state->undo_rec + state->redo_point-1,
13099 state->undo_rec + state->redo_point, num * sizeof(state->undo_rec[0]));
13100 }
13101}
13102
13103NK_INTERN struct nk_text_undo_record*
13104nk_textedit_create_undo_record(struct nk_text_undo_state *state, int numchars)
13105{
13106 /* any time we create a new undo record, we discard redo*/
13107 nk_textedit_flush_redo(state);
13108
13109 /* if we have no free records, we have to make room,
13110 * by sliding the existing records down */
13111 if (state->undo_point == NK_TEXTEDIT_UNDOSTATECOUNT)
13112 nk_textedit_discard_undo(state);
13113
13114 /* if the characters to store won't possibly fit in the buffer,
13115 * we can't undo */
13116 if (numchars > NK_TEXTEDIT_UNDOCHARCOUNT) {
13117 state->undo_point = 0;
13118 state->undo_char_point = 0;
13119 return 0;
13120 }
13121
13122 /* if we don't have enough free characters in the buffer,
13123 * we have to make room */
13124 while (state->undo_char_point + numchars > NK_TEXTEDIT_UNDOCHARCOUNT)
13125 nk_textedit_discard_undo(state);
13126 return &state->undo_rec[state->undo_point++];
13127}
13128
13129NK_INTERN nk_rune*
13130nk_textedit_createundo(struct nk_text_undo_state *state, int pos,
13131 int insert_len, int delete_len)
13132{
13133 struct nk_text_undo_record *r = nk_textedit_create_undo_record(state, insert_len);
13134 if (r == 0)
13135 return 0;
13136
13137 r->where = pos;
13138 r->insert_length = (short) insert_len;
13139 r->delete_length = (short) delete_len;
13140
13141 if (insert_len == 0) {
13142 r->char_storage = -1;
13143 return 0;
13144 } else {
13145 r->char_storage = state->undo_char_point;
13146 state->undo_char_point = (short)(state->undo_char_point + insert_len);
13147 return &state->undo_char[r->char_storage];
13148 }
13149}
13150
13151NK_API void
13152nk_textedit_undo(struct nk_text_edit *state)
13153{
13154 struct nk_text_undo_state *s = &state->undo;
13155 struct nk_text_undo_record u, *r;
13156 if (s->undo_point == 0)
13157 return;
13158
13159 /* we need to do two things: apply the undo record, and create a redo record */
13160 u = s->undo_rec[s->undo_point-1];
13161 r = &s->undo_rec[s->redo_point-1];
13162 r->char_storage = -1;
13163
13164 r->insert_length = u.delete_length;
13165 r->delete_length = u.insert_length;
13166 r->where = u.where;
13167
13168 if (u.delete_length)
13169 {
13170 /* if the undo record says to delete characters, then the redo record will
13171 need to re-insert the characters that get deleted, so we need to store
13172 them.
13173 there are three cases:
13174 - there's enough room to store the characters
13175 - characters stored for *redoing* don't leave room for redo
13176 - characters stored for *undoing* don't leave room for redo
13177 if the last is true, we have to bail */
13178 if (s->undo_char_point + u.delete_length >= NK_TEXTEDIT_UNDOCHARCOUNT) {
13179 /* the undo records take up too much character space; there's no space
13180 * to store the redo characters */
13181 r->insert_length = 0;
13182 } else {
13183 int i;
13184 /* there's definitely room to store the characters eventually */
13185 while (s->undo_char_point + u.delete_length > s->redo_char_point) {
13186 /* there's currently not enough room, so discard a redo record */
13187 nk_textedit_discard_redo(s);
13188 /* should never happen: */
13189 if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)
13190 return;
13191 }
13192
13193 r = &s->undo_rec[s->redo_point-1];
13194 r->char_storage = (short)(s->redo_char_point - u.delete_length);
13195 s->redo_char_point = (short)(s->redo_char_point - u.delete_length);
13196
13197 /* now save the characters */
13198 for (i=0; i < u.delete_length; ++i)
13199 s->undo_char[r->char_storage + i] =
13200 nk_str_rune_at(&state->string, u.where + i);
13201 }
13202 /* now we can carry out the deletion */
13203 nk_str_delete_runes(&state->string, u.where, u.delete_length);
13204 }
13205
13206 /* check type of recorded action: */
13207 if (u.insert_length) {
13208 /* easy case: was a deletion, so we need to insert n characters */
13209 nk_str_insert_text_runes(&state->string, u.where,
13210 &s->undo_char[u.char_storage], u.insert_length);
13211 s->undo_char_point = (short)(s->undo_char_point - u.insert_length);
13212 }
13213 state->cursor = (short)(u.where + u.insert_length);
13214
13215 s->undo_point--;
13216 s->redo_point--;
13217}
13218
13219NK_API void
13220nk_textedit_redo(struct nk_text_edit *state)
13221{
13222 struct nk_text_undo_state *s = &state->undo;
13223 struct nk_text_undo_record *u, r;
13224 if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)
13225 return;
13226
13227 /* we need to do two things: apply the redo record, and create an undo record */
13228 u = &s->undo_rec[s->undo_point];
13229 r = s->undo_rec[s->redo_point];
13230
13231 /* we KNOW there must be room for the undo record, because the redo record
13232 was derived from an undo record */
13233 u->delete_length = r.insert_length;
13234 u->insert_length = r.delete_length;
13235 u->where = r.where;
13236 u->char_storage = -1;
13237
13238 if (r.delete_length) {
13239 /* the redo record requires us to delete characters, so the undo record
13240 needs to store the characters */
13241 if (s->undo_char_point + u->insert_length > s->redo_char_point) {
13242 u->insert_length = 0;
13243 u->delete_length = 0;
13244 } else {
13245 int i;
13246 u->char_storage = s->undo_char_point;
13247 s->undo_char_point = (short)(s->undo_char_point + u->insert_length);
13248
13249 /* now save the characters */
13250 for (i=0; i < u->insert_length; ++i) {
13251 s->undo_char[u->char_storage + i] =
13252 nk_str_rune_at(&state->string, u->where + i);
13253 }
13254 }
13255 nk_str_delete_runes(&state->string, r.where, r.delete_length);
13256 }
13257
13258 if (r.insert_length) {
13259 /* easy case: need to insert n characters */
13260 nk_str_insert_text_runes(&state->string, r.where,
13261 &s->undo_char[r.char_storage], r.insert_length);
13262 }
13263 state->cursor = r.where + r.insert_length;
13264
13265 s->undo_point++;
13266 s->redo_point++;
13267}
13268
13269NK_INTERN void
13270nk_textedit_makeundo_insert(struct nk_text_edit *state, int where, int length)
13271{
13272 nk_textedit_createundo(&state->undo, where, 0, length);
13273}
13274
13275NK_INTERN void
13276nk_textedit_makeundo_delete(struct nk_text_edit *state, int where, int length)
13277{
13278 int i;
13279 nk_rune *p = nk_textedit_createundo(&state->undo, where, length, 0);
13280 if (p) {
13281 for (i=0; i < length; ++i)
13282 p[i] = nk_str_rune_at(&state->string, where+i);
13283 }
13284}
13285
13286NK_INTERN void
13287nk_textedit_makeundo_replace(struct nk_text_edit *state, int where,
13288 int old_length, int new_length)
13289{
13290 int i;
13291 nk_rune *p = nk_textedit_createundo(&state->undo, where, old_length, new_length);
13292 if (p) {
13293 for (i=0; i < old_length; ++i)
13294 p[i] = nk_str_rune_at(&state->string, where+i);
13295 }
13296}
13297
13298NK_INTERN void
13299nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type,
13300 nk_plugin_filter filter)
13301{
13302 /* reset the state to default */
13303 state->undo.undo_point = 0;
13304 state->undo.undo_char_point = 0;
13305 state->undo.redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;
13306 state->undo.redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;
13307 state->select_end = state->select_start = 0;
13308 state->cursor = 0;
13309 state->has_preferred_x = 0;
13310 state->preferred_x = 0;
13311 state->cursor_at_end_of_line = 0;
13312 state->initialized = 1;
13313 state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE);
13314 state->mode = NK_TEXT_EDIT_MODE_VIEW;
13315 state->filter = filter;
13316 state->scrollbar = nk_vec2(0,0);
13317}
13318
13319NK_API void
13320nk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size)
13321{
13322 NK_ASSERT(state);
13323 NK_ASSERT(memory);
13324 if (!state || !memory || !size) return;
13325 nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);
13326 nk_str_init_fixed(&state->string, memory, size);
13327}
13328
13329NK_API void
13330nk_textedit_init(struct nk_text_edit *state, struct nk_allocator *alloc, nk_size size)
13331{
13332 NK_ASSERT(state);
13333 NK_ASSERT(alloc);
13334 if (!state || !alloc) return;
13335 nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);
13336 nk_str_init(&state->string, alloc, size);
13337}
13338
13339#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
13340NK_API void
13341nk_textedit_init_default(struct nk_text_edit *state)
13342{
13343 NK_ASSERT(state);
13344 if (!state) return;
13345 nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);
13346 nk_str_init_default(&state->string);
13347}
13348#endif
13349
13350NK_API void
13351nk_textedit_select_all(struct nk_text_edit *state)
13352{
13353 NK_ASSERT(state);
13354 state->select_start = 0;
13355 state->select_end = state->string.len;
13356}
13357
13358NK_API void
13359nk_textedit_free(struct nk_text_edit *state)
13360{
13361 NK_ASSERT(state);
13362 if (!state) return;
13363 nk_str_free(&state->string);
13364}
13365
13366/* ===============================================================
13367 *
13368 * TEXT WIDGET
13369 *
13370 * ===============================================================*/
13371#define nk_widget_state_reset(s)\
13372 if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\
13373 (*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\
13374 else (*(s)) = NK_WIDGET_STATE_INACTIVE;
13375
13376struct nk_text {
13377 struct nk_vec2 padding;
13378 struct nk_color background;
13379 struct nk_color text;
13380};
13381
13382NK_INTERN void
13383nk_widget_text(struct nk_command_buffer *o, struct nk_rect b,
13384 const char *string, int len, const struct nk_text *t,
13385 nk_flags a, const struct nk_user_font *f)
13386{
13387 struct nk_rect label;
13388 float text_width;
13389
13390 NK_ASSERT(o);
13391 NK_ASSERT(t);
13392 if (!o || !t) return;
13393
13394 b.h = NK_MAX(b.h, 2 * t->padding.y);
13395 label.x = 0; label.w = 0;
13396 label.y = b.y + t->padding.y;
13397 label.h = NK_MIN(f->height, b.h - 2 * t->padding.y);
13398
13399 text_width = f->width(f->userdata, f->height, (const char*)string, len);
13400 text_width += (2.0f * t->padding.x);
13401
13402 /* align in x-axis */
13403 if (a & NK_TEXT_ALIGN_LEFT) {
13404 label.x = b.x + t->padding.x;
13405 label.w = NK_MAX(0, b.w - 2 * t->padding.x);
13406 } else if (a & NK_TEXT_ALIGN_CENTERED) {
13407 label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width);
13408 label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2);
13409 label.x = NK_MAX(b.x + t->padding.x, label.x);
13410 label.w = NK_MIN(b.x + b.w, label.x + label.w);
13411 if (label.w >= label.x) label.w -= label.x;
13412 } else if (a & NK_TEXT_ALIGN_RIGHT) {
13413 label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width));
13414 label.w = (float)text_width + 2 * t->padding.x;
13415 } else return;
13416
13417 /* align in y-axis */
13418 if (a & NK_TEXT_ALIGN_MIDDLE) {
13419 label.y = b.y + b.h/2.0f - (float)f->height/2.0f;
13420 label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f));
13421 } else if (a & NK_TEXT_ALIGN_BOTTOM) {
13422 label.y = b.y + b.h - f->height;
13423 label.h = f->height;
13424 }
13425 nk_draw_text(o, label, (const char*)string,
13426 len, f, t->background, t->text);
13427}
13428
13429NK_INTERN void
13430nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b,
13431 const char *string, int len, const struct nk_text *t,
13432 const struct nk_user_font *f)
13433{
13434 float width;
13435 int glyphs = 0;
13436 int fitting = 0;
13437 int done = 0;
13438 struct nk_rect line;
13439 struct nk_text text;
13440 NK_INTERN nk_rune seperator[] = {' '};
13441
13442 NK_ASSERT(o);
13443 NK_ASSERT(t);
13444 if (!o || !t) return;
13445
13446 text.padding = nk_vec2(0,0);
13447 text.background = t->background;
13448 text.text = t->text;
13449
13450 b.w = NK_MAX(b.w, 2 * t->padding.x);
13451 b.h = NK_MAX(b.h, 2 * t->padding.y);
13452 b.h = b.h - 2 * t->padding.y;
13453
13454 line.x = b.x + t->padding.x;
13455 line.y = b.y + t->padding.y;
13456 line.w = b.w - 2 * t->padding.x;
13457 line.h = 2 * t->padding.y + f->height;
13458
13459 fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator));
13460 while (done < len) {
13461 if (!fitting || line.y + line.h >= (b.y + b.h)) break;
13462 nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f);
13463 done += fitting;
13464 line.y += f->height + 2 * t->padding.y;
13465 fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator));
13466 }
13467}
13468
13469/* ===============================================================
13470 *
13471 * BUTTON
13472 *
13473 * ===============================================================*/
13474NK_INTERN void
13475nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type,
13476 struct nk_rect content, struct nk_color background, struct nk_color foreground,
13477 float border_width, const struct nk_user_font *font)
13478{
13479 switch (type) {
13480 case NK_SYMBOL_X:
13481 case NK_SYMBOL_UNDERSCORE:
13482 case NK_SYMBOL_PLUS:
13483 case NK_SYMBOL_MINUS: {
13484 /* single character text symbol */
13485 const char *X = (type == NK_SYMBOL_X) ? "x":
13486 (type == NK_SYMBOL_UNDERSCORE) ? "_":
13487 (type == NK_SYMBOL_PLUS) ? "+": "-";
13488 struct nk_text text;
13489 text.padding = nk_vec2(0,0);
13490 text.background = background;
13491 text.text = foreground;
13492 nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font);
13493 } break;
13494 case NK_SYMBOL_CIRCLE_SOLID:
13495 case NK_SYMBOL_CIRCLE_OUTLINE:
13496 case NK_SYMBOL_RECT_SOLID:
13497 case NK_SYMBOL_RECT_OUTLINE: {
13498 /* simple empty/filled shapes */
13499 if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) {
13500 nk_fill_rect(out, content, 0, foreground);
13501 if (type == NK_SYMBOL_RECT_OUTLINE)
13502 nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background);
13503 } else {
13504 nk_fill_circle(out, content, foreground);
13505 if (type == NK_SYMBOL_CIRCLE_OUTLINE)
13506 nk_fill_circle(out, nk_shrink_rect(content, 1), background);
13507 }
13508 } break;
13509 case NK_SYMBOL_TRIANGLE_UP:
13510 case NK_SYMBOL_TRIANGLE_DOWN:
13511 case NK_SYMBOL_TRIANGLE_LEFT:
13512 case NK_SYMBOL_TRIANGLE_RIGHT: {
13513 enum nk_heading heading;
13514 struct nk_vec2 points[3];
13515 heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT :
13516 (type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT:
13517 (type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN;
13518 nk_triangle_from_direction(points, content, 0, 0, heading);
13519 nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y,
13520 points[2].x, points[2].y, foreground);
13521 } break;
13522 default:
13523 case NK_SYMBOL_NONE:
13524 case NK_SYMBOL_MAX: break;
13525 }
13526}
13527
13528NK_INTERN int
13529nk_button_behavior(nk_flags *state, struct nk_rect r,
13530 const struct nk_input *i, enum nk_button_behavior behavior)
13531{
13532 int ret = 0;
13533 nk_widget_state_reset(state);
13534 if (!i) return 0;
13535 if (nk_input_is_mouse_hovering_rect(i, r)) {
13536 *state = NK_WIDGET_STATE_HOVERED;
13537 if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT))
13538 *state = NK_WIDGET_STATE_ACTIVE;
13539 if (nk_input_has_mouse_click_in_rect(i, NK_BUTTON_LEFT, r)) {
13540 ret = (behavior != NK_BUTTON_DEFAULT) ?
13541 nk_input_is_mouse_down(i, NK_BUTTON_LEFT):
13542#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
13543 nk_input_is_mouse_released(i, NK_BUTTON_LEFT);
13544#else
13545 nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT);
13546#endif
13547 }
13548 }
13549 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r))
13550 *state |= NK_WIDGET_STATE_ENTERED;
13551 else if (nk_input_is_mouse_prev_hovering_rect(i, r))
13552 *state |= NK_WIDGET_STATE_LEFT;
13553 return ret;
13554}
13555
13556NK_INTERN const struct nk_style_item*
13557nk_draw_button(struct nk_command_buffer *out,
13558 const struct nk_rect *bounds, nk_flags state,
13559 const struct nk_style_button *style)
13560{
13561 const struct nk_style_item *background;
13562 if (state & NK_WIDGET_STATE_HOVER)
13563 background = &style->hover;
13564 else if (state & NK_WIDGET_STATE_ACTIVED)
13565 background = &style->active;
13566 else background = &style->normal;
13567
13568 if (background->type == NK_STYLE_ITEM_IMAGE) {
13569 nk_draw_image(out, *bounds, &background->data.image, nk_white);
13570 } else {
13571 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
13572 nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
13573 }
13574 return background;
13575}
13576
13577NK_INTERN int
13578nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r,
13579 const struct nk_style_button *style, const struct nk_input *in,
13580 enum nk_button_behavior behavior, struct nk_rect *content)
13581{
13582 struct nk_rect bounds;
13583 NK_ASSERT(style);
13584 NK_ASSERT(state);
13585 NK_ASSERT(out);
13586 if (!out || !style)
13587 return nk_false;
13588
13589 /* calculate button content space */
13590 content->x = r.x + style->padding.x + style->border + style->rounding;
13591 content->y = r.y + style->padding.y + style->border + style->rounding;
13592 content->w = r.w - (2 * style->padding.x + style->border + style->rounding*2);
13593 content->h = r.h - (2 * style->padding.y + style->border + style->rounding*2);
13594
13595 /* execute button behavior */
13596 bounds.x = r.x - style->touch_padding.x;
13597 bounds.y = r.y - style->touch_padding.y;
13598 bounds.w = r.w + 2 * style->touch_padding.x;
13599 bounds.h = r.h + 2 * style->touch_padding.y;
13600 return nk_button_behavior(state, bounds, in, behavior);
13601}
13602
13603NK_INTERN void
13604nk_draw_button_text(struct nk_command_buffer *out,
13605 const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state,
13606 const struct nk_style_button *style, const char *txt, int len,
13607 nk_flags text_alignment, const struct nk_user_font *font)
13608{
13609 struct nk_text text;
13610 const struct nk_style_item *background;
13611 background = nk_draw_button(out, bounds, state, style);
13612
13613 /* select correct colors/images */
13614 if (background->type == NK_STYLE_ITEM_COLOR)
13615 text.background = background->data.color;
13616 else text.background = style->text_background;
13617 if (state & NK_WIDGET_STATE_HOVER)
13618 text.text = style->text_hover;
13619 else if (state & NK_WIDGET_STATE_ACTIVED)
13620 text.text = style->text_active;
13621 else text.text = style->text_normal;
13622
13623 text.padding = nk_vec2(0,0);
13624 nk_widget_text(out, *content, txt, len, &text, text_alignment, font);
13625}
13626
13627NK_INTERN int
13628nk_do_button_text(nk_flags *state,
13629 struct nk_command_buffer *out, struct nk_rect bounds,
13630 const char *string, int len, nk_flags align, enum nk_button_behavior behavior,
13631 const struct nk_style_button *style, const struct nk_input *in,
13632 const struct nk_user_font *font)
13633{
13634 struct nk_rect content;
13635 int ret = nk_false;
13636
13637 NK_ASSERT(state);
13638 NK_ASSERT(style);
13639 NK_ASSERT(out);
13640 NK_ASSERT(string);
13641 NK_ASSERT(font);
13642 if (!out || !style || !font || !string)
13643 return nk_false;
13644
13645 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
13646 if (style->draw_begin) style->draw_begin(out, style->userdata);
13647 nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font);
13648 if (style->draw_end) style->draw_end(out, style->userdata);
13649 return ret;
13650}
13651
13652NK_INTERN void
13653nk_draw_button_symbol(struct nk_command_buffer *out,
13654 const struct nk_rect *bounds, const struct nk_rect *content,
13655 nk_flags state, const struct nk_style_button *style,
13656 enum nk_symbol_type type, const struct nk_user_font *font)
13657{
13658 struct nk_color sym, bg;
13659 const struct nk_style_item *background;
13660
13661 /* select correct colors/images */
13662 background = nk_draw_button(out, bounds, state, style);
13663 if (background->type == NK_STYLE_ITEM_COLOR)
13664 bg = background->data.color;
13665 else bg = style->text_background;
13666
13667 if (state & NK_WIDGET_STATE_HOVER)
13668 sym = style->text_hover;
13669 else if (state & NK_WIDGET_STATE_ACTIVED)
13670 sym = style->text_active;
13671 else sym = style->text_normal;
13672 nk_draw_symbol(out, type, *content, bg, sym, 1, font);
13673}
13674
13675NK_INTERN int
13676nk_do_button_symbol(nk_flags *state,
13677 struct nk_command_buffer *out, struct nk_rect bounds,
13678 enum nk_symbol_type symbol, enum nk_button_behavior behavior,
13679 const struct nk_style_button *style, const struct nk_input *in,
13680 const struct nk_user_font *font)
13681{
13682 int ret;
13683 struct nk_rect content;
13684
13685 NK_ASSERT(state);
13686 NK_ASSERT(style);
13687 NK_ASSERT(font);
13688 NK_ASSERT(out);
13689 if (!out || !style || !font || !state)
13690 return nk_false;
13691
13692 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
13693 if (style->draw_begin) style->draw_begin(out, style->userdata);
13694 nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font);
13695 if (style->draw_end) style->draw_end(out, style->userdata);
13696 return ret;
13697}
13698
13699NK_INTERN void
13700nk_draw_button_image(struct nk_command_buffer *out,
13701 const struct nk_rect *bounds, const struct nk_rect *content,
13702 nk_flags state, const struct nk_style_button *style, const struct nk_image *img)
13703{
13704 nk_draw_button(out, bounds, state, style);
13705 nk_draw_image(out, *content, img, nk_white);
13706}
13707
13708NK_INTERN int
13709nk_do_button_image(nk_flags *state,
13710 struct nk_command_buffer *out, struct nk_rect bounds,
13711 struct nk_image img, enum nk_button_behavior b,
13712 const struct nk_style_button *style, const struct nk_input *in)
13713{
13714 int ret;
13715 struct nk_rect content;
13716
13717 NK_ASSERT(state);
13718 NK_ASSERT(style);
13719 NK_ASSERT(out);
13720 if (!out || !style || !state)
13721 return nk_false;
13722
13723 ret = nk_do_button(state, out, bounds, style, in, b, &content);
13724 content.x += style->image_padding.x;
13725 content.y += style->image_padding.y;
13726 content.w -= 2 * style->image_padding.x;
13727 content.h -= 2 * style->image_padding.y;
13728
13729 if (style->draw_begin) style->draw_begin(out, style->userdata);
13730 nk_draw_button_image(out, &bounds, &content, *state, style, &img);
13731 if (style->draw_end) style->draw_end(out, style->userdata);
13732 return ret;
13733}
13734
13735NK_INTERN void
13736nk_draw_button_text_symbol(struct nk_command_buffer *out,
13737 const struct nk_rect *bounds, const struct nk_rect *label,
13738 const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style,
13739 const char *str, int len, enum nk_symbol_type type,
13740 const struct nk_user_font *font)
13741{
13742 struct nk_color sym;
13743 struct nk_text text;
13744 const struct nk_style_item *background;
13745
13746 /* select correct background colors/images */
13747 background = nk_draw_button(out, bounds, state, style);
13748 if (background->type == NK_STYLE_ITEM_COLOR)
13749 text.background = background->data.color;
13750 else text.background = style->text_background;
13751
13752 /* select correct text colors */
13753 if (state & NK_WIDGET_STATE_HOVER) {
13754 sym = style->text_hover;
13755 text.text = style->text_hover;
13756 } else if (state & NK_WIDGET_STATE_ACTIVED) {
13757 sym = style->text_active;
13758 text.text = style->text_active;
13759 } else {
13760 sym = style->text_normal;
13761 text.text = style->text_normal;
13762 }
13763
13764 text.padding = nk_vec2(0,0);
13765 nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font);
13766 nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);
13767}
13768
13769NK_INTERN int
13770nk_do_button_text_symbol(nk_flags *state,
13771 struct nk_command_buffer *out, struct nk_rect bounds,
13772 enum nk_symbol_type symbol, const char *str, int len, nk_flags align,
13773 enum nk_button_behavior behavior, const struct nk_style_button *style,
13774 const struct nk_user_font *font, const struct nk_input *in)
13775{
13776 int ret;
13777 struct nk_rect tri = {0,0,0,0};
13778 struct nk_rect content;
13779
13780 NK_ASSERT(style);
13781 NK_ASSERT(out);
13782 NK_ASSERT(font);
13783 if (!out || !style || !font)
13784 return nk_false;
13785
13786 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
13787 tri.y = content.y + (content.h/2) - font->height/2;
13788 tri.w = font->height; tri.h = font->height;
13789 if (align & NK_TEXT_ALIGN_LEFT) {
13790 tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w);
13791 tri.x = NK_MAX(tri.x, 0);
13792 } else tri.x = content.x + 2 * style->padding.x;
13793
13794 /* draw button */
13795 if (style->draw_begin) style->draw_begin(out, style->userdata);
13796 nk_draw_button_text_symbol(out, &bounds, &content, &tri,
13797 *state, style, str, len, symbol, font);
13798 if (style->draw_end) style->draw_end(out, style->userdata);
13799 return ret;
13800}
13801
13802NK_INTERN void
13803nk_draw_button_text_image(struct nk_command_buffer *out,
13804 const struct nk_rect *bounds, const struct nk_rect *label,
13805 const struct nk_rect *image, nk_flags state, const struct nk_style_button *style,
13806 const char *str, int len, const struct nk_user_font *font,
13807 const struct nk_image *img)
13808{
13809 struct nk_text text;
13810 const struct nk_style_item *background;
13811 background = nk_draw_button(out, bounds, state, style);
13812
13813 /* select correct colors */
13814 if (background->type == NK_STYLE_ITEM_COLOR)
13815 text.background = background->data.color;
13816 else text.background = style->text_background;
13817 if (state & NK_WIDGET_STATE_HOVER)
13818 text.text = style->text_hover;
13819 else if (state & NK_WIDGET_STATE_ACTIVED)
13820 text.text = style->text_active;
13821 else text.text = style->text_normal;
13822
13823 text.padding = nk_vec2(0,0);
13824 nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);
13825 nk_draw_image(out, *image, img, nk_white);
13826}
13827
13828NK_INTERN int
13829nk_do_button_text_image(nk_flags *state,
13830 struct nk_command_buffer *out, struct nk_rect bounds,
13831 struct nk_image img, const char* str, int len, nk_flags align,
13832 enum nk_button_behavior behavior, const struct nk_style_button *style,
13833 const struct nk_user_font *font, const struct nk_input *in)
13834{
13835 int ret;
13836 struct nk_rect icon;
13837 struct nk_rect content;
13838
13839 NK_ASSERT(style);
13840 NK_ASSERT(state);
13841 NK_ASSERT(font);
13842 NK_ASSERT(out);
13843 if (!out || !font || !style || !str)
13844 return nk_false;
13845
13846 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
13847 icon.y = bounds.y + style->padding.y;
13848 icon.w = icon.h = bounds.h - 2 * style->padding.y;
13849 if (align & NK_TEXT_ALIGN_LEFT) {
13850 icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);
13851 icon.x = NK_MAX(icon.x, 0);
13852 } else icon.x = bounds.x + 2 * style->padding.x;
13853
13854 icon.x += style->image_padding.x;
13855 icon.y += style->image_padding.y;
13856 icon.w -= 2 * style->image_padding.x;
13857 icon.h -= 2 * style->image_padding.y;
13858
13859 if (style->draw_begin) style->draw_begin(out, style->userdata);
13860 nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img);
13861 if (style->draw_end) style->draw_end(out, style->userdata);
13862 return ret;
13863}
13864
13865/* ===============================================================
13866 *
13867 * TOGGLE
13868 *
13869 * ===============================================================*/
13870enum nk_toggle_type {
13871 NK_TOGGLE_CHECK,
13872 NK_TOGGLE_OPTION
13873};
13874
13875NK_INTERN int
13876nk_toggle_behavior(const struct nk_input *in, struct nk_rect select,
13877 nk_flags *state, int active)
13878{
13879 nk_widget_state_reset(state);
13880 if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) {
13881 *state = NK_WIDGET_STATE_ACTIVE;
13882 active = !active;
13883 }
13884 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select))
13885 *state |= NK_WIDGET_STATE_ENTERED;
13886 else if (nk_input_is_mouse_prev_hovering_rect(in, select))
13887 *state |= NK_WIDGET_STATE_LEFT;
13888 return active;
13889}
13890
13891NK_INTERN void
13892nk_draw_checkbox(struct nk_command_buffer *out,
13893 nk_flags state, const struct nk_style_toggle *style, int active,
13894 const struct nk_rect *label, const struct nk_rect *selector,
13895 const struct nk_rect *cursors, const char *string, int len,
13896 const struct nk_user_font *font)
13897{
13898 const struct nk_style_item *background;
13899 const struct nk_style_item *cursor;
13900 struct nk_text text;
13901
13902 /* select correct colors/images */
13903 if (state & NK_WIDGET_STATE_HOVER) {
13904 background = &style->hover;
13905 cursor = &style->cursor_hover;
13906 text.text = style->text_hover;
13907 } else if (state & NK_WIDGET_STATE_ACTIVED) {
13908 background = &style->hover;
13909 cursor = &style->cursor_hover;
13910 text.text = style->text_active;
13911 } else {
13912 background = &style->normal;
13913 cursor = &style->cursor_normal;
13914 text.text = style->text_normal;
13915 }
13916
13917 /* draw background and cursor */
13918 if (background->type == NK_STYLE_ITEM_COLOR) {
13919 nk_fill_rect(out, *selector, 0, style->border_color);
13920 nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, background->data.color);
13921 } else nk_draw_image(out, *selector, &background->data.image, nk_white);
13922 if (active) {
13923 if (cursor->type == NK_STYLE_ITEM_IMAGE)
13924 nk_draw_image(out, *cursors, &cursor->data.image, nk_white);
13925 else nk_fill_rect(out, *cursors, 0, cursor->data.color);
13926 }
13927
13928 text.padding.x = 0;
13929 text.padding.y = 0;
13930 text.background = style->text_background;
13931 nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font);
13932}
13933
13934NK_INTERN void
13935nk_draw_option(struct nk_command_buffer *out,
13936 nk_flags state, const struct nk_style_toggle *style, int active,
13937 const struct nk_rect *label, const struct nk_rect *selector,
13938 const struct nk_rect *cursors, const char *string, int len,
13939 const struct nk_user_font *font)
13940{
13941 const struct nk_style_item *background;
13942 const struct nk_style_item *cursor;
13943 struct nk_text text;
13944
13945 /* select correct colors/images */
13946 if (state & NK_WIDGET_STATE_HOVER) {
13947 background = &style->hover;
13948 cursor = &style->cursor_hover;
13949 text.text = style->text_hover;
13950 } else if (state & NK_WIDGET_STATE_ACTIVED) {
13951 background = &style->hover;
13952 cursor = &style->cursor_hover;
13953 text.text = style->text_active;
13954 } else {
13955 background = &style->normal;
13956 cursor = &style->cursor_normal;
13957 text.text = style->text_normal;
13958 }
13959
13960 /* draw background and cursor */
13961 if (background->type == NK_STYLE_ITEM_COLOR) {
13962 nk_fill_circle(out, *selector, style->border_color);
13963 nk_fill_circle(out, nk_shrink_rect(*selector, style->border), background->data.color);
13964 } else nk_draw_image(out, *selector, &background->data.image, nk_white);
13965 if (active) {
13966 if (cursor->type == NK_STYLE_ITEM_IMAGE)
13967 nk_draw_image(out, *cursors, &cursor->data.image, nk_white);
13968 else nk_fill_circle(out, *cursors, cursor->data.color);
13969 }
13970
13971 text.padding.x = 0;
13972 text.padding.y = 0;
13973 text.background = style->text_background;
13974 nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font);
13975}
13976
13977NK_INTERN int
13978nk_do_toggle(nk_flags *state,
13979 struct nk_command_buffer *out, struct nk_rect r,
13980 int *active, const char *str, int len, enum nk_toggle_type type,
13981 const struct nk_style_toggle *style, const struct nk_input *in,
13982 const struct nk_user_font *font)
13983{
13984 int was_active;
13985 struct nk_rect bounds;
13986 struct nk_rect select;
13987 struct nk_rect cursor;
13988 struct nk_rect label;
13989
13990 NK_ASSERT(style);
13991 NK_ASSERT(out);
13992 NK_ASSERT(font);
13993 if (!out || !style || !font || !active)
13994 return 0;
13995
13996 r.w = NK_MAX(r.w, font->height + 2 * style->padding.x);
13997 r.h = NK_MAX(r.h, font->height + 2 * style->padding.y);
13998
13999 /* add additional touch padding for touch screen devices */
14000 bounds.x = r.x - style->touch_padding.x;
14001 bounds.y = r.y - style->touch_padding.y;
14002 bounds.w = r.w + 2 * style->touch_padding.x;
14003 bounds.h = r.h + 2 * style->touch_padding.y;
14004
14005 /* calculate the selector space */
14006 select.w = font->height;
14007 select.h = select.w;
14008 select.y = r.y + r.h/2.0f - select.h/2.0f;
14009 select.x = r.x;
14010
14011 /* calculate the bounds of the cursor inside the selector */
14012 cursor.x = select.x + style->padding.x + style->border;
14013 cursor.y = select.y + style->padding.y + style->border;
14014 cursor.w = select.w - (2 * style->padding.x + 2 * style->border);
14015 cursor.h = select.h - (2 * style->padding.y + 2 * style->border);
14016
14017 /* label behind the selector */
14018 label.x = select.x + select.w + style->spacing;
14019 label.y = select.y;
14020 label.w = NK_MAX(r.x + r.w, label.x) - label.x;
14021 label.h = select.w;
14022
14023 /* update selector */
14024 was_active = *active;
14025 *active = nk_toggle_behavior(in, bounds, state, *active);
14026
14027 /* draw selector */
14028 if (style->draw_begin)
14029 style->draw_begin(out, style->userdata);
14030 if (type == NK_TOGGLE_CHECK) {
14031 nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font);
14032 } else {
14033 nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font);
14034 }
14035 if (style->draw_end)
14036 style->draw_end(out, style->userdata);
14037 return (was_active != *active);
14038}
14039
14040/* ===============================================================
14041 *
14042 * SELECTABLE
14043 *
14044 * ===============================================================*/
14045NK_INTERN void
14046nk_draw_selectable(struct nk_command_buffer *out,
14047 nk_flags state, const struct nk_style_selectable *style, int active,
14048 const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img,
14049 const char *string, int len, nk_flags align, const struct nk_user_font *font)
14050{
14051 const struct nk_style_item *background;
14052 struct nk_text text;
14053 text.padding = style->padding;
14054
14055 /* select correct colors/images */
14056 if (!active) {
14057 if (state & NK_WIDGET_STATE_ACTIVED) {
14058 background = &style->pressed;
14059 text.text = style->text_pressed;
14060 } else if (state & NK_WIDGET_STATE_HOVER) {
14061 background = &style->hover;
14062 text.text = style->text_hover;
14063 } else {
14064 background = &style->normal;
14065 text.text = style->text_normal;
14066 }
14067 } else {
14068 if (state & NK_WIDGET_STATE_ACTIVED) {
14069 background = &style->pressed_active;
14070 text.text = style->text_pressed_active;
14071 } else if (state & NK_WIDGET_STATE_HOVER) {
14072 background = &style->hover_active;
14073 text.text = style->text_hover_active;
14074 } else {
14075 background = &style->normal_active;
14076 text.text = style->text_normal_active;
14077 }
14078 }
14079
14080
14081 /* draw selectable background and text */
14082 if (background->type == NK_STYLE_ITEM_IMAGE) {
14083 nk_draw_image(out, *bounds, &background->data.image, nk_white);
14084 text.background = nk_rgba(0,0,0,0);
14085 } else {
14086 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
14087 text.background = background->data.color;
14088 }
14089 if (img && icon) nk_draw_image(out, *icon, img, nk_white);
14090 nk_widget_text(out, *bounds, string, len, &text, align, font);
14091}
14092
14093NK_INTERN int
14094nk_do_selectable(nk_flags *state, struct nk_command_buffer *out,
14095 struct nk_rect bounds, const char *str, int len, nk_flags align, int *value,
14096 const struct nk_style_selectable *style, const struct nk_input *in,
14097 const struct nk_user_font *font)
14098{
14099 int old_value;
14100 struct nk_rect touch;
14101
14102 NK_ASSERT(state);
14103 NK_ASSERT(out);
14104 NK_ASSERT(str);
14105 NK_ASSERT(len);
14106 NK_ASSERT(value);
14107 NK_ASSERT(style);
14108 NK_ASSERT(font);
14109
14110 if (!state || !out || !str || !len || !value || !style || !font) return 0;
14111 old_value = *value;
14112
14113 /* remove padding */
14114 touch.x = bounds.x - style->touch_padding.x;
14115 touch.y = bounds.y - style->touch_padding.y;
14116 touch.w = bounds.w + style->touch_padding.x * 2;
14117 touch.h = bounds.h + style->touch_padding.y * 2;
14118
14119 /* update button */
14120 if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))
14121 *value = !(*value);
14122
14123 /* draw selectable */
14124 if (style->draw_begin) style->draw_begin(out, style->userdata);
14125 nk_draw_selectable(out, *state, style, *value, &bounds, 0,0, str, len, align, font);
14126 if (style->draw_end) style->draw_end(out, style->userdata);
14127 return old_value != *value;
14128}
14129
14130NK_INTERN int
14131nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out,
14132 struct nk_rect bounds, const char *str, int len, nk_flags align, int *value,
14133 const struct nk_image *img, const struct nk_style_selectable *style,
14134 const struct nk_input *in, const struct nk_user_font *font)
14135{
14136 int old_value;
14137 struct nk_rect touch;
14138 struct nk_rect icon;
14139
14140 NK_ASSERT(state);
14141 NK_ASSERT(out);
14142 NK_ASSERT(str);
14143 NK_ASSERT(len);
14144 NK_ASSERT(value);
14145 NK_ASSERT(style);
14146 NK_ASSERT(font);
14147
14148 if (!state || !out || !str || !len || !value || !style || !font) return 0;
14149 old_value = *value;
14150
14151 /* toggle behavior */
14152 touch.x = bounds.x - style->touch_padding.x;
14153 touch.y = bounds.y - style->touch_padding.y;
14154 touch.w = bounds.w + style->touch_padding.x * 2;
14155 touch.h = bounds.h + style->touch_padding.y * 2;
14156 if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))
14157 *value = !(*value);
14158
14159 icon.y = bounds.y + style->padding.y;
14160 icon.w = icon.h = bounds.h - 2 * style->padding.y;
14161 if (align & NK_TEXT_ALIGN_LEFT) {
14162 icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);
14163 icon.x = NK_MAX(icon.x, 0);
14164 } else icon.x = bounds.x + 2 * style->padding.x;
14165
14166 icon.x += style->image_padding.x;
14167 icon.y += style->image_padding.y;
14168 icon.w -= 2 * style->image_padding.x;
14169 icon.h -= 2 * style->image_padding.y;
14170
14171 /* draw selectable */
14172 if (style->draw_begin) style->draw_begin(out, style->userdata);
14173 nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, str, len, align, font);
14174 if (style->draw_end) style->draw_end(out, style->userdata);
14175 return old_value != *value;
14176}
14177
14178
14179/* ===============================================================
14180 *
14181 * SLIDER
14182 *
14183 * ===============================================================*/
14184NK_INTERN float
14185nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor,
14186 struct nk_rect *visual_cursor, struct nk_input *in,
14187 struct nk_rect bounds, float slider_min, float slider_max, float slider_value,
14188 float slider_step, float slider_steps)
14189{
14190 int left_mouse_down;
14191 int left_mouse_click_in_cursor;
14192
14193 /* check if visual cursor is being dragged */
14194 nk_widget_state_reset(state);
14195 left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
14196 left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,
14197 NK_BUTTON_LEFT, *visual_cursor, nk_true);
14198
14199 if (left_mouse_down && left_mouse_click_in_cursor)
14200 {
14201 float ratio = 0;
14202 const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f);
14203 const float pxstep = bounds.w / slider_steps;
14204
14205 /* only update value if the next slider step is reached */
14206 *state = NK_WIDGET_STATE_ACTIVE;
14207 if (NK_ABS(d) >= pxstep) {
14208 const float steps = (float)((int)(NK_ABS(d) / pxstep));
14209 slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps);
14210 slider_value = NK_CLAMP(slider_min, slider_value, slider_max);
14211 ratio = (slider_value - slider_min)/slider_step;
14212 logical_cursor->x = bounds.x + (logical_cursor->w * ratio);
14213 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x;
14214 }
14215 }
14216
14217 /* slider widget state */
14218 if (nk_input_is_mouse_hovering_rect(in, bounds))
14219 *state = NK_WIDGET_STATE_HOVERED;
14220 if (*state & NK_WIDGET_STATE_HOVER &&
14221 !nk_input_is_mouse_prev_hovering_rect(in, bounds))
14222 *state |= NK_WIDGET_STATE_ENTERED;
14223 else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))
14224 *state |= NK_WIDGET_STATE_LEFT;
14225 return slider_value;
14226}
14227
14228NK_INTERN void
14229nk_draw_slider(struct nk_command_buffer *out, nk_flags state,
14230 const struct nk_style_slider *style, const struct nk_rect *bounds,
14231 const struct nk_rect *visual_cursor, float min, float value, float max)
14232{
14233 struct nk_rect fill;
14234 struct nk_rect bar;
14235 const struct nk_style_item *background;
14236
14237 /* select correct slider images/colors */
14238 struct nk_color bar_color;
14239 const struct nk_style_item *cursor;
14240
14241 NK_UNUSED(min);
14242 NK_UNUSED(max);
14243 NK_UNUSED(value);
14244
14245 if (state & NK_WIDGET_STATE_ACTIVED) {
14246 background = &style->active;
14247 bar_color = style->bar_active;
14248 cursor = &style->cursor_active;
14249 } else if (state & NK_WIDGET_STATE_HOVER) {
14250 background = &style->hover;
14251 bar_color = style->bar_hover;
14252 cursor = &style->cursor_hover;
14253 } else {
14254 background = &style->normal;
14255 bar_color = style->bar_normal;
14256 cursor = &style->cursor_normal;
14257 }
14258
14259 /* calculate slider background bar */
14260 bar.x = bounds->x;
14261 bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12;
14262 bar.w = bounds->w;
14263 bar.h = bounds->h/6;
14264
14265 /* filled background bar style */
14266 fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x;
14267 fill.x = bar.x;
14268 fill.y = bar.y;
14269 fill.h = bar.h;
14270
14271 /* draw background */
14272 if (background->type == NK_STYLE_ITEM_IMAGE) {
14273 nk_draw_image(out, *bounds, &background->data.image, nk_white);
14274 } else {
14275 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
14276 nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
14277 }
14278
14279 /* draw slider bar */
14280 nk_fill_rect(out, bar, style->rounding, bar_color);
14281 nk_fill_rect(out, fill, style->rounding, style->bar_filled);
14282
14283 /* draw cursor */
14284 if (cursor->type == NK_STYLE_ITEM_IMAGE)
14285 nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_white);
14286 else nk_fill_circle(out, *visual_cursor, cursor->data.color);
14287}
14288
14289NK_INTERN float
14290nk_do_slider(nk_flags *state,
14291 struct nk_command_buffer *out, struct nk_rect bounds,
14292 float min, float val, float max, float step,
14293 const struct nk_style_slider *style, struct nk_input *in,
14294 const struct nk_user_font *font)
14295{
14296 float slider_range;
14297 float slider_min;
14298 float slider_max;
14299 float slider_value;
14300 float slider_steps;
14301 float cursor_offset;
14302
14303 struct nk_rect visual_cursor;
14304 struct nk_rect logical_cursor;
14305
14306 NK_ASSERT(style);
14307 NK_ASSERT(out);
14308 if (!out || !style)
14309 return 0;
14310
14311 /* remove padding from slider bounds */
14312 bounds.x = bounds.x + style->padding.x;
14313 bounds.y = bounds.y + style->padding.y;
14314 bounds.h = NK_MAX(bounds.h, 2*style->padding.y);
14315 bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x);
14316 bounds.w -= 2 * style->padding.x;
14317 bounds.h -= 2 * style->padding.y;
14318
14319 /* optional buttons */
14320 if (style->show_buttons) {
14321 nk_flags ws;
14322 struct nk_rect button;
14323 button.y = bounds.y;
14324 button.w = bounds.h;
14325 button.h = bounds.h;
14326
14327 /* decrement button */
14328 button.x = bounds.x;
14329 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT,
14330 &style->dec_button, in, font))
14331 val -= step;
14332
14333 /* increment button */
14334 button.x = (bounds.x + bounds.w) - button.w;
14335 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT,
14336 &style->inc_button, in, font))
14337 val += step;
14338
14339 bounds.x = bounds.x + button.w + style->spacing.x;
14340 bounds.w = bounds.w - (2*button.w + 2*style->spacing.x);
14341 }
14342
14343 /* remove one cursor size to support visual cursor */
14344 bounds.x += style->cursor_size.x*0.5f;
14345 bounds.w -= style->cursor_size.x;
14346
14347 /* make sure the provided values are correct */
14348 slider_max = NK_MAX(min, max);
14349 slider_min = NK_MIN(min, max);
14350 slider_value = NK_CLAMP(slider_min, val, slider_max);
14351 slider_range = slider_max - slider_min;
14352 slider_steps = slider_range / step;
14353 cursor_offset = (slider_value - slider_min) / step;
14354
14355 /* calculate cursor
14356 Basically you have two cursors. One for visual representation and interaction
14357 and one for updating the actual cursor value. */
14358 logical_cursor.h = bounds.h;
14359 logical_cursor.w = bounds.w / slider_steps;
14360 logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset);
14361 logical_cursor.y = bounds.y;
14362
14363 visual_cursor.h = style->cursor_size.y;
14364 visual_cursor.w = style->cursor_size.x;
14365 visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f;
14366 visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
14367
14368 slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor,
14369 in, bounds, slider_min, slider_max, slider_value, step, slider_steps);
14370 visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
14371
14372 /* draw slider */
14373 if (style->draw_begin) style->draw_begin(out, style->userdata);
14374 nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max);
14375 if (style->draw_end) style->draw_end(out, style->userdata);
14376 return slider_value;
14377}
14378
14379/* ===============================================================
14380 *
14381 * PROGRESSBAR
14382 *
14383 * ===============================================================*/
14384NK_INTERN nk_size
14385nk_progress_behavior(nk_flags *state, const struct nk_input *in,
14386 struct nk_rect r, nk_size max, nk_size value, int modifiable)
14387{
14388 nk_widget_state_reset(state);
14389 if (in && modifiable && nk_input_is_mouse_hovering_rect(in, r)) {
14390 int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
14391 int left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
14392 NK_BUTTON_LEFT, r, nk_true);
14393
14394 if (left_mouse_down && left_mouse_click_in_cursor) {
14395 float ratio = NK_MAX(0, (float)(in->mouse.pos.x - r.x)) / (float)r.w;
14396 value = (nk_size)NK_MAX(0,((float)max * ratio));
14397 *state = NK_WIDGET_STATE_ACTIVE;
14398 } else *state = NK_WIDGET_STATE_HOVERED;
14399 }
14400
14401 /* set progressbar widget state */
14402 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r))
14403 *state |= NK_WIDGET_STATE_ENTERED;
14404 else if (nk_input_is_mouse_prev_hovering_rect(in, r))
14405 *state |= NK_WIDGET_STATE_LEFT;
14406
14407 if (!max) return value;
14408 value = NK_MIN(value, max);
14409 return value;
14410}
14411
14412NK_INTERN void
14413nk_draw_progress(struct nk_command_buffer *out, nk_flags state,
14414 const struct nk_style_progress *style, const struct nk_rect *bounds,
14415 const struct nk_rect *scursor, nk_size value, nk_size max)
14416{
14417 const struct nk_style_item *background;
14418 const struct nk_style_item *cursor;
14419
14420 NK_UNUSED(max);
14421 NK_UNUSED(value);
14422
14423 /* select correct colors/images to draw */
14424 if (state & NK_WIDGET_STATE_ACTIVED) {
14425 background = &style->active;
14426 cursor = &style->cursor_active;
14427 } else if (state & NK_WIDGET_STATE_HOVER){
14428 background = &style->hover;
14429 cursor = &style->cursor_hover;
14430 } else {
14431 background = &style->normal;
14432 cursor = &style->cursor_normal;
14433 }
14434
14435 /* draw background */
14436 if (background->type == NK_STYLE_ITEM_COLOR) {
14437 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
14438 nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
14439 } else nk_draw_image(out, *bounds, &background->data.image, nk_white);
14440
14441 /* draw cursor */
14442 if (background->type == NK_STYLE_ITEM_COLOR) {
14443 nk_fill_rect(out, *scursor, style->rounding, cursor->data.color);
14444 nk_stroke_rect(out, *scursor, style->rounding, style->border, style->border_color);
14445 } else nk_draw_image(out, *scursor, &cursor->data.image, nk_white);
14446}
14447
14448NK_INTERN nk_size
14449nk_do_progress(nk_flags *state,
14450 struct nk_command_buffer *out, struct nk_rect bounds,
14451 nk_size value, nk_size max, int modifiable,
14452 const struct nk_style_progress *style, const struct nk_input *in)
14453{
14454 float prog_scale;
14455 nk_size prog_value;
14456 struct nk_rect cursor;
14457
14458 NK_ASSERT(style);
14459 NK_ASSERT(out);
14460 if (!out || !style) return 0;
14461
14462 /* calculate progressbar cursor */
14463 cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border);
14464 cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border);
14465 cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border));
14466 prog_scale = (float)value / (float)max;
14467 cursor.w = (bounds.w - 2) * prog_scale;
14468
14469 /* update progressbar */
14470 prog_value = NK_MIN(value, max);
14471 prog_value = nk_progress_behavior(state, in, bounds, max, prog_value, modifiable);
14472
14473 /* draw progressbar */
14474 if (style->draw_begin) style->draw_begin(out, style->userdata);
14475 nk_draw_progress(out, *state, style, &bounds, &cursor, value, max);
14476 if (style->draw_end) style->draw_end(out, style->userdata);
14477 return prog_value;
14478}
14479
14480/* ===============================================================
14481 *
14482 * SCROLLBAR
14483 *
14484 * ===============================================================*/
14485NK_INTERN float
14486nk_scrollbar_behavior(nk_flags *state, struct nk_input *in,
14487 int has_scrolling, const struct nk_rect *scroll,
14488 const struct nk_rect *cursor, const struct nk_rect *empty0,
14489 const struct nk_rect *empty1, float scroll_offset,
14490 float target, float scroll_step, enum nk_orientation o)
14491{
14492 nk_flags ws = 0;
14493 int left_mouse_down;
14494 int left_mouse_click_in_cursor;
14495 float scroll_delta;
14496
14497 nk_widget_state_reset(state);
14498 if (!in) return scroll_offset;
14499
14500 left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
14501 left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
14502 NK_BUTTON_LEFT, *cursor, nk_true);
14503 if (nk_input_is_mouse_hovering_rect(in, *scroll))
14504 *state = NK_WIDGET_STATE_HOVERED;
14505
14506 scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x;
14507 if (left_mouse_down && left_mouse_click_in_cursor) {
14508 /* update cursor by mouse dragging */
14509 float pixel, delta;
14510 *state = NK_WIDGET_STATE_ACTIVE;
14511 if (o == NK_VERTICAL) {
14512 float cursor_y;
14513 pixel = in->mouse.delta.y;
14514 delta = (pixel / scroll->h) * target;
14515 scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h);
14516 cursor_y = scroll->y + ((scroll_offset/target) * scroll->h);
14517 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f;
14518 } else {
14519 float cursor_x;
14520 pixel = in->mouse.delta.x;
14521 delta = (pixel / scroll->w) * target;
14522 scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w);
14523 cursor_x = scroll->x + ((scroll_offset/target) * scroll->w);
14524 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f;
14525 }
14526 } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)||
14527 nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) {
14528 /* scroll page up by click on empty space or shortcut */
14529 if (o == NK_VERTICAL)
14530 scroll_offset = NK_MAX(0, scroll_offset - scroll->h);
14531 else scroll_offset = NK_MAX(0, scroll_offset - scroll->w);
14532 } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) ||
14533 nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) {
14534 /* scroll page down by click on empty space or shortcut */
14535 if (o == NK_VERTICAL)
14536 scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h);
14537 else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w);
14538 } else if (has_scrolling) {
14539 if ((scroll_delta < 0 || (scroll_delta > 0))) {
14540 /* update cursor by mouse scrolling */
14541 scroll_offset = scroll_offset + scroll_step * (-scroll_delta);
14542 if (o == NK_VERTICAL)
14543 scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h);
14544 else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w);
14545 } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) {
14546 /* update cursor to the beginning */
14547 if (o == NK_VERTICAL) scroll_offset = 0;
14548 } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) {
14549 /* update cursor to the end */
14550 if (o == NK_VERTICAL) scroll_offset = target - scroll->h;
14551 }
14552 }
14553 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll))
14554 *state |= NK_WIDGET_STATE_ENTERED;
14555 else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll))
14556 *state |= NK_WIDGET_STATE_LEFT;
14557 return scroll_offset;
14558}
14559
14560NK_INTERN void
14561nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state,
14562 const struct nk_style_scrollbar *style, const struct nk_rect *bounds,
14563 const struct nk_rect *scroll)
14564{
14565 const struct nk_style_item *background;
14566 const struct nk_style_item *cursor;
14567
14568 /* select correct colors/images to draw */
14569 if (state & NK_WIDGET_STATE_ACTIVED) {
14570 background = &style->active;
14571 cursor = &style->cursor_active;
14572 } else if (state & NK_WIDGET_STATE_HOVER) {
14573 background = &style->hover;
14574 cursor = &style->cursor_hover;
14575 } else {
14576 background = &style->normal;
14577 cursor = &style->cursor_normal;
14578 }
14579
14580 /* draw background */
14581 if (background->type == NK_STYLE_ITEM_COLOR) {
14582 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
14583 nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
14584 } else {
14585 nk_draw_image(out, *bounds, &background->data.image, nk_white);
14586 }
14587
14588 /* draw cursor */
14589 if (background->type == NK_STYLE_ITEM_COLOR) {
14590 nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color);
14591 nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color);
14592 } else nk_draw_image(out, *scroll, &cursor->data.image, nk_white);
14593}
14594
14595NK_INTERN float
14596nk_do_scrollbarv(nk_flags *state,
14597 struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,
14598 float offset, float target, float step, float button_pixel_inc,
14599 const struct nk_style_scrollbar *style, struct nk_input *in,
14600 const struct nk_user_font *font)
14601{
14602 struct nk_rect empty_north;
14603 struct nk_rect empty_south;
14604 struct nk_rect cursor;
14605
14606 float scroll_step;
14607 float scroll_offset;
14608 float scroll_off;
14609 float scroll_ratio;
14610
14611 NK_ASSERT(out);
14612 NK_ASSERT(style);
14613 NK_ASSERT(state);
14614 if (!out || !style) return 0;
14615
14616 scroll.w = NK_MAX(scroll.w, 1);
14617 scroll.h = NK_MAX(scroll.h, 2 * scroll.w);
14618 if (target <= scroll.h) return 0;
14619
14620 /* optional scrollbar buttons */
14621 if (style->show_buttons) {
14622 nk_flags ws;
14623 float scroll_h;
14624 struct nk_rect button;
14625
14626 button.x = scroll.x;
14627 button.w = scroll.w;
14628 button.h = scroll.w;
14629
14630 scroll_h = scroll.h - 2 * button.h;
14631 scroll_step = NK_MIN(step, button_pixel_inc);
14632
14633 /* decrement button */
14634 button.y = scroll.y;
14635 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,
14636 NK_BUTTON_REPEATER, &style->dec_button, in, font))
14637 offset = offset - scroll_step;
14638
14639 /* increment button */
14640 button.y = scroll.y + scroll.h - button.h;
14641 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,
14642 NK_BUTTON_REPEATER, &style->inc_button, in, font))
14643 offset = offset + scroll_step;
14644
14645 scroll.y = scroll.y + button.h;
14646 scroll.h = scroll_h;
14647 }
14648
14649 /* calculate scrollbar constants */
14650 scroll_step = NK_MIN(step, scroll.h);
14651 scroll_offset = NK_CLAMP(0, offset, target - scroll.h);
14652 scroll_ratio = scroll.h / target;
14653 scroll_off = scroll_offset / target;
14654
14655 /* calculate scrollbar cursor bounds */
14656 cursor.h = (scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y);
14657 cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y;
14658 cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x);
14659 cursor.x = scroll.x + style->border + style->padding.x;
14660
14661 /* calculate empty space around cursor */
14662 empty_north.x = scroll.x;
14663 empty_north.y = scroll.y;
14664 empty_north.w = scroll.w;
14665 empty_north.h = cursor.y - scroll.y;
14666
14667 empty_south.x = scroll.x;
14668 empty_south.y = cursor.y + cursor.h;
14669 empty_south.w = scroll.w;
14670 empty_south.h = (scroll.y + scroll.h) - (cursor.y + cursor.h);
14671
14672 /* update scrollbar */
14673 scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,
14674 &empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL);
14675 scroll_off = scroll_offset / target;
14676 cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y;
14677
14678 /* draw scrollbar */
14679 if (style->draw_begin) style->draw_begin(out, style->userdata);
14680 nk_draw_scrollbar(out, *state, style, &scroll, &cursor);
14681 if (style->draw_end) style->draw_end(out, style->userdata);
14682 return scroll_offset;
14683}
14684
14685NK_INTERN float
14686nk_do_scrollbarh(nk_flags *state,
14687 struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,
14688 float offset, float target, float step, float button_pixel_inc,
14689 const struct nk_style_scrollbar *style, struct nk_input *in,
14690 const struct nk_user_font *font)
14691{
14692 struct nk_rect cursor;
14693 struct nk_rect empty_west;
14694 struct nk_rect empty_east;
14695
14696 float scroll_step;
14697 float scroll_offset;
14698 float scroll_off;
14699 float scroll_ratio;
14700
14701 NK_ASSERT(out);
14702 NK_ASSERT(style);
14703 if (!out || !style) return 0;
14704
14705 /* scrollbar background */
14706 scroll.h = NK_MAX(scroll.h, 1);
14707 scroll.w = NK_MAX(scroll.w, 2 * scroll.h);
14708 if (target <= scroll.w) return 0;
14709
14710 /* optional scrollbar buttons */
14711 if (style->show_buttons) {
14712 nk_flags ws;
14713 float scroll_w;
14714 struct nk_rect button;
14715 button.y = scroll.y;
14716 button.w = scroll.h;
14717 button.h = scroll.h;
14718
14719 scroll_w = scroll.w - 2 * button.w;
14720 scroll_step = NK_MIN(step, button_pixel_inc);
14721
14722 /* decrement button */
14723 button.x = scroll.x;
14724 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,
14725 NK_BUTTON_REPEATER, &style->dec_button, in, font))
14726 offset = offset - scroll_step;
14727
14728 /* increment button */
14729 button.x = scroll.x + scroll.w - button.w;
14730 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,
14731 NK_BUTTON_REPEATER, &style->inc_button, in, font))
14732 offset = offset + scroll_step;
14733
14734 scroll.x = scroll.x + button.w;
14735 scroll.w = scroll_w;
14736 }
14737
14738 /* calculate scrollbar constants */
14739 scroll_step = NK_MIN(step, scroll.w);
14740 scroll_offset = NK_CLAMP(0, offset, target - scroll.w);
14741 scroll_ratio = scroll.w / target;
14742 scroll_off = scroll_offset / target;
14743
14744 /* calculate cursor bounds */
14745 cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x);
14746 cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x;
14747 cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y);
14748 cursor.y = scroll.y + style->border + style->padding.y;
14749
14750 /* calculate empty space around cursor */
14751 empty_west.x = scroll.x;
14752 empty_west.y = scroll.y;
14753 empty_west.w = cursor.x - scroll.x;
14754 empty_west.h = scroll.h;
14755
14756 empty_east.x = cursor.x + cursor.w;
14757 empty_east.y = scroll.y;
14758 empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w);
14759 empty_east.h = scroll.h;
14760
14761 /* update scrollbar */
14762 scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,
14763 &empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL);
14764 scroll_off = scroll_offset / target;
14765 cursor.x = scroll.x + (scroll_off * scroll.w);
14766
14767 /* draw scrollbar */
14768 if (style->draw_begin) style->draw_begin(out, style->userdata);
14769 nk_draw_scrollbar(out, *state, style, &scroll, &cursor);
14770 if (style->draw_end) style->draw_end(out, style->userdata);
14771 return scroll_offset;
14772}
14773
14774/* ===============================================================
14775 *
14776 * FILTER
14777 *
14778 * ===============================================================*/
14779NK_API int nk_filter_default(const struct nk_text_edit *box, nk_rune unicode)
14780{(void)unicode;NK_UNUSED(box);return nk_true;}
14781
14782NK_API int
14783nk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode)
14784{
14785 NK_UNUSED(box);
14786 if (unicode > 128) return nk_false;
14787 else return nk_true;
14788}
14789
14790NK_API int
14791nk_filter_float(const struct nk_text_edit *box, nk_rune unicode)
14792{
14793 NK_UNUSED(box);
14794 if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-')
14795 return nk_false;
14796 else return nk_true;
14797}
14798
14799NK_API int
14800nk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode)
14801{
14802 NK_UNUSED(box);
14803 if ((unicode < '0' || unicode > '9') && unicode != '-')
14804 return nk_false;
14805 else return nk_true;
14806}
14807
14808NK_API int
14809nk_filter_hex(const struct nk_text_edit *box, nk_rune unicode)
14810{
14811 NK_UNUSED(box);
14812 if ((unicode < '0' || unicode > '9') &&
14813 (unicode < 'a' || unicode > 'f') &&
14814 (unicode < 'A' || unicode > 'F'))
14815 return nk_false;
14816 else return nk_true;
14817}
14818
14819NK_API int
14820nk_filter_oct(const struct nk_text_edit *box, nk_rune unicode)
14821{
14822 NK_UNUSED(box);
14823 if (unicode < '0' || unicode > '7')
14824 return nk_false;
14825 else return nk_true;
14826}
14827
14828NK_API int
14829nk_filter_binary(const struct nk_text_edit *box, nk_rune unicode)
14830{
14831 NK_UNUSED(box);
14832 if (unicode != '0' && unicode != '1')
14833 return nk_false;
14834 else return nk_true;
14835}
14836
14837/* ===============================================================
14838 *
14839 * EDIT
14840 *
14841 * ===============================================================*/
14842NK_INTERN void
14843nk_edit_draw_text(struct nk_command_buffer *out,
14844 const struct nk_style_edit *style, float pos_x, float pos_y,
14845 float x_offset, const char *text, int byte_len, float row_height,
14846 const struct nk_user_font *font, struct nk_color background,
14847 struct nk_color foreground, int is_selected)
14848{
14849 NK_ASSERT(out);
14850 NK_ASSERT(font);
14851 NK_ASSERT(style);
14852 if (!text || !byte_len || !out || !style) return;
14853
14854 {int glyph_len = 0;
14855 nk_rune unicode = 0;
14856 int text_len = 0;
14857 float line_width = 0;
14858 float glyph_width;
14859 const char *line = text;
14860 float line_offset = 0;
14861 int line_count = 0;
14862
14863 struct nk_text txt;
14864 txt.padding = nk_vec2(0,0);
14865 txt.background = background;
14866 txt.text = foreground;
14867
14868 glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len);
14869 if (!glyph_len) return;
14870 while ((text_len < byte_len) && glyph_len)
14871 {
14872 if (unicode == '\n') {
14873 /* new line sepeator so draw previous line */
14874 struct nk_rect label;
14875 label.y = pos_y + line_offset;
14876 label.h = row_height;
14877 label.w = line_width;
14878 label.x = pos_x;
14879 if (!line_count)
14880 label.x += x_offset;
14881
14882 if (is_selected) /* selection needs to draw different background color */
14883 nk_fill_rect(out, label, 0, background);
14884 nk_widget_text(out, label, line, (int)((text + text_len) - line),
14885 &txt, NK_TEXT_CENTERED, font);
14886
14887 text_len++;
14888 line_count++;
14889 line_width = 0;
14890 line = text + text_len;
14891 line_offset += row_height;
14892 glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len));
14893 continue;
14894 }
14895 if (unicode == '\r') {
14896 text_len++;
14897 glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
14898 continue;
14899 }
14900 glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
14901 line_width += (float)glyph_width;
14902 text_len += glyph_len;
14903 glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
14904 continue;
14905 }
14906 if (line_width > 0) {
14907 /* draw last line */
14908 struct nk_rect label;
14909 label.y = pos_y + line_offset;
14910 label.h = row_height;
14911 label.w = line_width;
14912 label.x = pos_x;
14913 if (!line_count)
14914 label.x += x_offset;
14915
14916 if (is_selected)
14917 nk_fill_rect(out, label, 0, background);
14918 nk_widget_text(out, label, line, (int)((text + text_len) - line),
14919 &txt, NK_TEXT_LEFT, font);
14920 }}
14921}
14922
14923NK_INTERN nk_flags
14924nk_do_edit(nk_flags *state, struct nk_command_buffer *out,
14925 struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter,
14926 struct nk_text_edit *edit, const struct nk_style_edit *style,
14927 struct nk_input *in, const struct nk_user_font *font)
14928{
14929 struct nk_rect area;
14930 nk_flags ret = 0;
14931 float row_height;
14932 char prev_state = 0;
14933 char is_hovered = 0;
14934 char select_all = 0;
14935 char cursor_follow = 0;
14936 struct nk_rect old_clip;
14937 struct nk_rect clip;
14938
14939 NK_ASSERT(state);
14940 NK_ASSERT(out);
14941 NK_ASSERT(style);
14942 if (!state || !out || !style)
14943 return ret;
14944
14945 /* visible text area calculation */
14946 area.x = bounds.x + style->padding.x + style->border;
14947 area.y = bounds.y + style->padding.y + style->border;
14948 area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border);
14949 area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border);
14950 if (flags & NK_EDIT_MULTILINE)
14951 area.w = NK_MAX(0, area.w - style->scrollbar_size.x);
14952 row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h;
14953
14954 /* calculate clipping rectangle */
14955 old_clip = out->clip;
14956 nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h);
14957
14958 /* update edit state */
14959 prev_state = (char)edit->active;
14960 is_hovered = (char)nk_input_is_mouse_hovering_rect(in, bounds);
14961 if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) {
14962 edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y,
14963 bounds.x, bounds.y, bounds.w, bounds.h);
14964 }
14965
14966 /* (de)activate text editor */
14967 if (!prev_state && edit->active) {
14968 const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ?
14969 NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE;
14970 nk_textedit_clear_state(edit, type, filter);
14971 if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
14972 edit->mode = NK_TEXT_EDIT_MODE_INSERT;
14973 if (flags & NK_EDIT_AUTO_SELECT)
14974 select_all = nk_true;
14975 if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) {
14976 edit->cursor = edit->string.len;
14977 in = 0;
14978 }
14979 } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW;
14980 if (flags & NK_EDIT_READ_ONLY)
14981 edit->mode = NK_TEXT_EDIT_MODE_VIEW;
14982
14983 ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE;
14984 if (prev_state != edit->active)
14985 ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED;
14986
14987 /* handle user input */
14988 if (edit->active && in)
14989 {
14990 int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down;
14991 const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x;
14992 const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y;
14993
14994 /* mouse click handler */
14995 is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area);
14996 if (select_all) {
14997 nk_textedit_select_all(edit);
14998 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
14999 in->mouse.buttons[NK_BUTTON_LEFT].clicked) {
15000 nk_textedit_click(edit, mouse_x, mouse_y, font, row_height);
15001 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
15002 (in->mouse.delta.x != 0.0f || in->mouse.delta.y != 0.0f)) {
15003 nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height);
15004 cursor_follow = nk_true;
15005 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked &&
15006 in->mouse.buttons[NK_BUTTON_RIGHT].down) {
15007 nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height);
15008 nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height);
15009 cursor_follow = nk_true;
15010 }
15011
15012 {int i; /* keyboard input */
15013 int old_mode = edit->mode;
15014 for (i = 0; i < NK_KEY_MAX; ++i) {
15015 if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */
15016 if (nk_input_is_key_pressed(in, (enum nk_keys)i)) {
15017 nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height);
15018 cursor_follow = nk_true;
15019 }
15020 }
15021 if (old_mode != edit->mode) {
15022 in->keyboard.text_len = 0;
15023 }}
15024
15025 /* text input */
15026 edit->filter = filter;
15027 if (in->keyboard.text_len) {
15028 nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len);
15029 cursor_follow = nk_true;
15030 in->keyboard.text_len = 0;
15031 }
15032
15033 /* enter key handler */
15034 if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) {
15035 cursor_follow = nk_true;
15036 if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod)
15037 nk_textedit_text(edit, "\n", 1);
15038 else if (flags & NK_EDIT_SIG_ENTER)
15039 ret |= NK_EDIT_COMMITED;
15040 else nk_textedit_text(edit, "\n", 1);
15041 }
15042
15043 /* cut & copy handler */
15044 {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY);
15045 int cut = nk_input_is_key_pressed(in, NK_KEY_CUT);
15046 if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD))
15047 {
15048 int glyph_len;
15049 nk_rune unicode;
15050 const char *text;
15051 int b = edit->select_start;
15052 int e = edit->select_end;
15053
15054 int begin = NK_MIN(b, e);
15055 int end = NK_MAX(b, e);
15056 text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len);
15057 if (edit->clip.copy)
15058 edit->clip.copy(edit->clip.userdata, text, end - begin);
15059 if (cut && !(flags & NK_EDIT_READ_ONLY)){
15060 nk_textedit_cut(edit);
15061 cursor_follow = nk_true;
15062 }
15063 }}
15064
15065 /* paste handler */
15066 {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE);
15067 if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) {
15068 edit->clip.paste(edit->clip.userdata, edit);
15069 cursor_follow = nk_true;
15070 }}
15071
15072 /* tab handler */
15073 {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB);
15074 if (tab && (flags & NK_EDIT_ALLOW_TAB)) {
15075 nk_textedit_text(edit, " ", 4);
15076 cursor_follow = nk_true;
15077 }}
15078 }
15079
15080 /* set widget state */
15081 if (edit->active)
15082 *state = NK_WIDGET_STATE_ACTIVE;
15083 else nk_widget_state_reset(state);
15084
15085 if (is_hovered)
15086 *state |= NK_WIDGET_STATE_HOVERED;
15087
15088 /* DRAW EDIT */
15089 {const char *text = nk_str_get_const(&edit->string);
15090 int len = nk_str_len_char(&edit->string);
15091
15092 {/* select background colors/images */
15093 const struct nk_style_item *background;
15094 if (*state & NK_WIDGET_STATE_ACTIVED)
15095 background = &style->active;
15096 else if (*state & NK_WIDGET_STATE_HOVER)
15097 background = &style->hover;
15098 else background = &style->normal;
15099
15100 /* draw background frame */
15101 if (background->type == NK_STYLE_ITEM_COLOR) {
15102 nk_stroke_rect(out, bounds, style->rounding, style->border, style->border_color);
15103 nk_fill_rect(out, bounds, style->rounding, background->data.color);
15104 } else nk_draw_image(out, bounds, &background->data.image, nk_white);}
15105
15106 area.w = NK_MAX(0, area.w - style->cursor_size);
15107 if (edit->active)
15108 {
15109 int total_lines = 1;
15110 struct nk_vec2 text_size = nk_vec2(0,0);
15111
15112 /* text pointer positions */
15113 const char *cursor_ptr = 0;
15114 const char *select_begin_ptr = 0;
15115 const char *select_end_ptr = 0;
15116
15117 /* 2D pixel positions */
15118 struct nk_vec2 cursor_pos = nk_vec2(0,0);
15119 struct nk_vec2 selection_offset_start = nk_vec2(0,0);
15120 struct nk_vec2 selection_offset_end = nk_vec2(0,0);
15121
15122 int selection_begin = NK_MIN(edit->select_start, edit->select_end);
15123 int selection_end = NK_MAX(edit->select_start, edit->select_end);
15124
15125 /* calculate total line count + total space + cursor/selection position */
15126 float line_width = 0.0f;
15127 if (text && len)
15128 {
15129 /* utf8 encoding */
15130 float glyph_width;
15131 int glyph_len = 0;
15132 nk_rune unicode = 0;
15133 int text_len = 0;
15134 int glyphs = 0;
15135 int row_begin = 0;
15136
15137 glyph_len = nk_utf_decode(text, &unicode, len);
15138 glyph_width = font->width(font->userdata, font->height, text, glyph_len);
15139 line_width = 0;
15140
15141 /* iterate all lines */
15142 while ((text_len < len) && glyph_len)
15143 {
15144 /* set cursor 2D position and line */
15145 if (!cursor_ptr && glyphs == edit->cursor)
15146 {
15147 int glyph_offset;
15148 struct nk_vec2 out_offset;
15149 struct nk_vec2 row_size;
15150 const char *remaining;
15151
15152 /* calculate 2d position */
15153 cursor_pos.y = (float)(total_lines-1) * row_height;
15154 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
15155 text_len-row_begin, row_height, &remaining,
15156 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
15157 cursor_pos.x = row_size.x;
15158 cursor_ptr = text + text_len;
15159 }
15160
15161 /* set start selection 2D position and line */
15162 if (!select_begin_ptr && edit->select_start != edit->select_end &&
15163 glyphs == selection_begin)
15164 {
15165 int glyph_offset;
15166 struct nk_vec2 out_offset;
15167 struct nk_vec2 row_size;
15168 const char *remaining;
15169
15170 /* calculate 2d position */
15171 selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height;
15172 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
15173 text_len-row_begin, row_height, &remaining,
15174 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
15175 selection_offset_start.x = row_size.x;
15176 select_begin_ptr = text + text_len;
15177 }
15178
15179 /* set end selection 2D position and line */
15180 if (!select_end_ptr && edit->select_start != edit->select_end &&
15181 glyphs == selection_end)
15182 {
15183 int glyph_offset;
15184 struct nk_vec2 out_offset;
15185 struct nk_vec2 row_size;
15186 const char *remaining;
15187
15188 /* calculate 2d position */
15189 selection_offset_end.y = (float)(total_lines-1) * row_height;
15190 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
15191 text_len-row_begin, row_height, &remaining,
15192 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
15193 selection_offset_end.x = row_size.x;
15194 select_end_ptr = text + text_len;
15195 }
15196 if (unicode == '\n') {
15197 text_size.x = NK_MAX(text_size.x, line_width);
15198 total_lines++;
15199 line_width = 0;
15200 text_len++;
15201 glyphs++;
15202 row_begin = text_len;
15203 glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
15204 glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
15205 continue;
15206 }
15207
15208 glyphs++;
15209 text_len += glyph_len;
15210 line_width += (float)glyph_width;
15211
15212 glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
15213 glyph_width = font->width(font->userdata, font->height,
15214 text+text_len, glyph_len);
15215 continue;
15216 }
15217 text_size.y = (float)total_lines * row_height;
15218
15219 /* handle case when cursor is at end of text buffer */
15220 if (!cursor_ptr && edit->cursor == edit->string.len) {
15221 cursor_pos.x = line_width;
15222 cursor_pos.y = text_size.y - row_height;
15223 }
15224 }
15225 {
15226 /* scrollbar */
15227 if (cursor_follow)
15228 {
15229 /* update scrollbar to follow cursor */
15230 if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) {
15231 /* horizontal scroll */
15232 const float scroll_increment = area.w * 0.25f;
15233 if (cursor_pos.x < edit->scrollbar.x)
15234 edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment);
15235 if (cursor_pos.x >= edit->scrollbar.x + area.w)
15236 edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x);
15237 } else edit->scrollbar.x = 0;
15238
15239 if (flags & NK_EDIT_MULTILINE) {
15240 /* vertical scroll */
15241 if (cursor_pos.y < edit->scrollbar.y)
15242 edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y - row_height);
15243 if (cursor_pos.y >= edit->scrollbar.y + area.h)
15244 edit->scrollbar.y = edit->scrollbar.y + row_height;
15245 } else edit->scrollbar.y = 0;
15246 }
15247
15248 /* scrollbar widget */
15249 if (flags & NK_EDIT_MULTILINE)
15250 {
15251 nk_flags ws;
15252 struct nk_rect scroll;
15253 float scroll_target;
15254 float scroll_offset;
15255 float scroll_step;
15256 float scroll_inc;
15257
15258 scroll = area;
15259 scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x;
15260 scroll.w = style->scrollbar_size.x;
15261
15262 scroll_offset = edit->scrollbar.y;
15263 scroll_step = scroll.h * 0.10f;
15264 scroll_inc = scroll.h * 0.01f;
15265 scroll_target = text_size.y;
15266 edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, 0,
15267 scroll_offset, scroll_target, scroll_step, scroll_inc,
15268 &style->scrollbar, in, font);
15269 }
15270 }
15271
15272 /* draw text */
15273 {struct nk_color background_color;
15274 struct nk_color text_color;
15275 struct nk_color sel_background_color;
15276 struct nk_color sel_text_color;
15277 struct nk_color cursor_color;
15278 struct nk_color cursor_text_color;
15279 const struct nk_style_item *background;
15280 nk_push_scissor(out, clip);
15281
15282 /* select correct colors to draw */
15283 if (*state & NK_WIDGET_STATE_ACTIVED) {
15284 background = &style->active;
15285 text_color = style->text_active;
15286 sel_text_color = style->selected_text_hover;
15287 sel_background_color = style->selected_hover;
15288 cursor_color = style->cursor_hover;
15289 cursor_text_color = style->cursor_text_hover;
15290 } else if (*state & NK_WIDGET_STATE_HOVER) {
15291 background = &style->hover;
15292 text_color = style->text_hover;
15293 sel_text_color = style->selected_text_hover;
15294 sel_background_color = style->selected_hover;
15295 cursor_text_color = style->cursor_text_hover;
15296 cursor_color = style->cursor_hover;
15297 } else {
15298 background = &style->normal;
15299 text_color = style->text_normal;
15300 sel_text_color = style->selected_text_normal;
15301 sel_background_color = style->selected_normal;
15302 cursor_color = style->cursor_normal;
15303 cursor_text_color = style->cursor_text_normal;
15304 }
15305 if (background->type == NK_STYLE_ITEM_IMAGE)
15306 background_color = nk_rgba(0,0,0,0);
15307 else background_color = background->data.color;
15308
15309
15310 if (edit->select_start == edit->select_end) {
15311 /* no selection so just draw the complete text */
15312 const char *begin = nk_str_get_const(&edit->string);
15313 int l = nk_str_len_char(&edit->string);
15314 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
15315 area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
15316 background_color, text_color, nk_false);
15317 } else {
15318 /* edit has selection so draw 1-3 text chunks */
15319 if (edit->select_start != edit->select_end && selection_begin > 0){
15320 /* draw unselected text before selection */
15321 const char *begin = nk_str_get_const(&edit->string);
15322 NK_ASSERT(select_begin_ptr);
15323 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
15324 area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin),
15325 row_height, font, background_color, text_color, nk_false);
15326 }
15327 if (edit->select_start != edit->select_end) {
15328 /* draw selected text */
15329 NK_ASSERT(select_begin_ptr);
15330 if (!select_end_ptr) {
15331 const char *begin = nk_str_get_const(&edit->string);
15332 select_end_ptr = begin + nk_str_len_char(&edit->string);
15333 }
15334 nk_edit_draw_text(out, style,
15335 area.x - edit->scrollbar.x,
15336 area.y + selection_offset_start.y - edit->scrollbar.y,
15337 selection_offset_start.x,
15338 select_begin_ptr, (int)(select_end_ptr - select_begin_ptr),
15339 row_height, font, sel_background_color, sel_text_color, nk_true);
15340 }
15341 if ((edit->select_start != edit->select_end &&
15342 selection_end < edit->string.len))
15343 {
15344 /* draw unselected text after selected text */
15345 const char *begin = select_end_ptr;
15346 const char *end = nk_str_get_const(&edit->string) +
15347 nk_str_len_char(&edit->string);
15348 NK_ASSERT(select_end_ptr);
15349 nk_edit_draw_text(out, style,
15350 area.x - edit->scrollbar.x,
15351 area.y + selection_offset_end.y - edit->scrollbar.y,
15352 selection_offset_end.x,
15353 begin, (int)(end - begin), row_height, font,
15354 background_color, text_color, nk_true);
15355 }
15356 }
15357
15358 /* cursor */
15359 if (edit->select_start == edit->select_end)
15360 {
15361 if (edit->cursor >= nk_str_len(&edit->string) ||
15362 (cursor_ptr && *cursor_ptr == '\n')) {
15363 /* draw cursor at end of line */
15364 struct nk_rect cursor;
15365 cursor.w = style->cursor_size;
15366 cursor.h = font->height;
15367 cursor.x = area.x + cursor_pos.x - edit->scrollbar.x;
15368 cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f;
15369 cursor.y -= edit->scrollbar.y;
15370 nk_fill_rect(out, cursor, 0, cursor_color);
15371 } else {
15372 /* draw cursor inside text */
15373 int glyph_len;
15374 struct nk_rect label;
15375 struct nk_text txt;
15376
15377 nk_rune unicode;
15378 NK_ASSERT(cursor_ptr);
15379 glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4);
15380
15381 label.x = area.x + cursor_pos.x - edit->scrollbar.x;
15382 label.y = area.y + cursor_pos.y - edit->scrollbar.y;
15383 label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len);
15384 label.h = row_height;
15385
15386 txt.padding = nk_vec2(0,0);
15387 txt.background = cursor_color;;
15388 txt.text = cursor_text_color;
15389 nk_fill_rect(out, label, 0, cursor_color);
15390 nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font);
15391 }
15392 }}
15393 } else {
15394 /* not active so just draw text */
15395 int l = nk_str_len_char(&edit->string);
15396 const char *begin = nk_str_get_const(&edit->string);
15397
15398 const struct nk_style_item *background;
15399 struct nk_color background_color;
15400 struct nk_color text_color;
15401 nk_push_scissor(out, clip);
15402 if (*state & NK_WIDGET_STATE_ACTIVED) {
15403 background = &style->active;
15404 text_color = style->text_active;
15405 } else if (*state & NK_WIDGET_STATE_HOVER) {
15406 background = &style->hover;
15407 text_color = style->text_hover;
15408 } else {
15409 background = &style->normal;
15410 text_color = style->text_normal;
15411 }
15412 if (background->type == NK_STYLE_ITEM_IMAGE)
15413 background_color = nk_rgba(0,0,0,0);
15414 else background_color = background->data.color;
15415 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
15416 area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
15417 background_color, text_color, nk_false);
15418 }
15419 nk_push_scissor(out, old_clip);}
15420 return ret;
15421}
15422
15423/* ===============================================================
15424 *
15425 * PROPERTY
15426 *
15427 * ===============================================================*/
15428enum nk_property_status {
15429 NK_PROPERTY_DEFAULT,
15430 NK_PROPERTY_EDIT,
15431 NK_PROPERTY_DRAG
15432};
15433enum nk_property_filter {
15434 NK_FILTER_INT,
15435 NK_FILTER_FLOAT
15436};
15437enum nk_property_kind {
15438 NK_PROPERTY_INT,
15439 NK_PROPERTY_FLOAT,
15440 NK_PROPERTY_DOUBLE
15441};
15442union nk_property {
15443 int i;
15444 float f;
15445 double d;
15446};
15447struct nk_property_variant {
15448 enum nk_property_kind kind;
15449 union nk_property value;
15450 union nk_property min_value;
15451 union nk_property max_value;
15452 union nk_property step;
15453};
15454
15455NK_INTERN void
15456nk_drag_behavior(nk_flags *state, const struct nk_input *in,
15457 struct nk_rect drag, struct nk_property_variant *variant,
15458 float inc_per_pixel)
15459{
15460 int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
15461 int left_mouse_click_in_cursor = in &&
15462 nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true);
15463
15464 nk_widget_state_reset(state);
15465 if (nk_input_is_mouse_hovering_rect(in, drag))
15466 *state = NK_WIDGET_STATE_HOVERED;
15467
15468 if (left_mouse_down && left_mouse_click_in_cursor) {
15469 float delta, pixels;
15470 pixels = in->mouse.delta.x;
15471 delta = pixels * inc_per_pixel;
15472 switch (variant->kind) {
15473 default: break;
15474 case NK_PROPERTY_INT:
15475 variant->value.i = variant->value.i + (int)delta;
15476 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
15477 break;
15478 case NK_PROPERTY_FLOAT:
15479 variant->value.f = variant->value.f + (float)delta;
15480 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
15481 break;
15482 case NK_PROPERTY_DOUBLE:
15483 variant->value.d = variant->value.d + (double)delta;
15484 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
15485 break;
15486 }
15487 *state = NK_WIDGET_STATE_ACTIVE;
15488 }
15489 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag))
15490 *state |= NK_WIDGET_STATE_ENTERED;
15491 else if (nk_input_is_mouse_prev_hovering_rect(in, drag))
15492 *state |= NK_WIDGET_STATE_LEFT;
15493}
15494
15495NK_INTERN void
15496nk_property_behavior(nk_flags *ws, const struct nk_input *in,
15497 struct nk_rect property, struct nk_rect label, struct nk_rect edit,
15498 struct nk_rect empty, int *state, struct nk_property_variant *variant,
15499 float inc_per_pixel)
15500{
15501 if (in && *state == NK_PROPERTY_DEFAULT) {
15502 if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT))
15503 *state = NK_PROPERTY_EDIT;
15504 else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true))
15505 *state = NK_PROPERTY_DRAG;
15506 else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true))
15507 *state = NK_PROPERTY_DRAG;
15508 }
15509 if (*state == NK_PROPERTY_DRAG) {
15510 nk_drag_behavior(ws, in, property, variant, inc_per_pixel);
15511 if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT;
15512 }
15513}
15514
15515NK_INTERN void
15516nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style,
15517 const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state,
15518 const char *name, int len, const struct nk_user_font *font)
15519{
15520 struct nk_text text;
15521 const struct nk_style_item *background;
15522
15523 /* select correct background and text color */
15524 if (state & NK_WIDGET_STATE_ACTIVED) {
15525 background = &style->active;
15526 text.text = style->label_active;
15527 } else if (state & NK_WIDGET_STATE_HOVER) {
15528 background = &style->hover;
15529 text.text = style->label_hover;
15530 } else {
15531 background = &style->normal;
15532 text.text = style->label_normal;
15533 }
15534
15535 /* draw background */
15536 if (background->type == NK_STYLE_ITEM_IMAGE) {
15537 nk_draw_image(out, *bounds, &background->data.image, nk_white);
15538 text.background = nk_rgba(0,0,0,0);
15539 } else {
15540 text.background = background->data.color;
15541 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
15542 nk_stroke_rect(out, *bounds, style->rounding, style->border, background->data.color);
15543 }
15544
15545 /* draw label */
15546 text.padding = nk_vec2(0,0);
15547 nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font);
15548}
15549
15550NK_INTERN void
15551nk_do_property(nk_flags *ws,
15552 struct nk_command_buffer *out, struct nk_rect property,
15553 const char *name, struct nk_property_variant *variant,
15554 float inc_per_pixel, char *buffer, int *len,
15555 int *state, int *cursor, const struct nk_style_property *style,
15556 enum nk_property_filter filter, struct nk_input *in,
15557 const struct nk_user_font *font, struct nk_text_edit *text_edit)
15558{
15559 const nk_plugin_filter filters[] = {
15560 nk_filter_decimal,
15561 nk_filter_float
15562 };
15563 int active, old;
15564 int num_len, name_len;
15565 char string[NK_MAX_NUMBER_BUFFER];
15566 float size;
15567
15568 char *dst = 0;
15569 int *length;
15570
15571 struct nk_rect left;
15572 struct nk_rect right;
15573 struct nk_rect label;
15574 struct nk_rect edit;
15575 struct nk_rect empty;
15576
15577 /* left decrement button */
15578 left.h = font->height/2;
15579 left.w = left.h;
15580 left.x = property.x + style->border + style->padding.x;
15581 left.y = property.y + style->border + property.h/2.0f - left.h/2;
15582
15583 /* text label */
15584 name_len = nk_strlen(name);
15585 size = font->width(font->userdata, font->height, name, name_len);
15586 label.x = left.x + left.w + style->padding.x;
15587 label.w = (float)size + 2 * style->padding.x;
15588 label.y = property.y + style->border + style->padding.y;
15589 label.h = property.h - (2 * style->border + 2 * style->padding.y);
15590
15591 /* right increment button */
15592 right.y = left.y;
15593 right.w = left.w;
15594 right.h = left.h;
15595 right.x = property.x + property.w - (right.w + style->padding.x);
15596
15597 /* edit */
15598 if (*state == NK_PROPERTY_EDIT) {
15599 size = font->width(font->userdata, font->height, buffer, *len);
15600 size += style->edit.cursor_size;
15601 length = len;
15602 dst = buffer;
15603 } else {
15604 switch (variant->kind) {
15605 default: break;
15606 case NK_PROPERTY_INT:
15607 nk_itoa(string, variant->value.i);
15608 num_len = nk_strlen(string);
15609 break;
15610 case NK_PROPERTY_FLOAT:
15611 nk_dtoa(string, (double)variant->value.f);
15612 num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
15613 break;
15614 case NK_PROPERTY_DOUBLE:
15615 nk_dtoa(string, variant->value.d);
15616 num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
15617 break;
15618 }
15619 size = font->width(font->userdata, font->height, string, num_len);
15620 dst = string;
15621 length = &num_len;
15622 }
15623
15624 edit.w = (float)size + 2 * style->padding.x;
15625 edit.w = NK_MIN(edit.w, right.x - (label.x + label.w));
15626 edit.x = right.x - (edit.w + style->padding.x);
15627 edit.y = property.y + style->border;
15628 edit.h = property.h - (2 * style->border);
15629
15630 /* empty left space activator */
15631 empty.w = edit.x - (label.x + label.w);
15632 empty.x = label.x + label.w;
15633 empty.y = property.y;
15634 empty.h = property.h;
15635
15636 /* update property */
15637 old = (*state == NK_PROPERTY_EDIT);
15638 nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel);
15639
15640 /* draw property */
15641 if (style->draw_begin) style->draw_begin(out, style->userdata);
15642 nk_draw_property(out, style, &property, &label, *ws, name, name_len, font);
15643 if (style->draw_end) style->draw_end(out, style->userdata);
15644
15645 /* execute right button */
15646 if (nk_do_button_symbol(ws, out, left, style->sym_left, NK_BUTTON_DEFAULT, &style->dec_button, in, font)) {
15647 switch (variant->kind) {
15648 default: break;
15649 case NK_PROPERTY_INT:
15650 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break;
15651 case NK_PROPERTY_FLOAT:
15652 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break;
15653 case NK_PROPERTY_DOUBLE:
15654 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break;
15655 }
15656 }
15657
15658 /* execute left button */
15659 if (nk_do_button_symbol(ws, out, right, style->sym_right, NK_BUTTON_DEFAULT, &style->inc_button, in, font)) {
15660 switch (variant->kind) {
15661 default: break;
15662 case NK_PROPERTY_INT:
15663 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break;
15664 case NK_PROPERTY_FLOAT:
15665 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break;
15666 case NK_PROPERTY_DOUBLE:
15667 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break;
15668 }
15669 }
15670
15671 active = (*state == NK_PROPERTY_EDIT);
15672 if (old != NK_PROPERTY_EDIT && active) {
15673 /* property has been activated so setup buffer */
15674 NK_MEMCPY(buffer, dst, (nk_size)*length);
15675 *cursor = nk_utf_len(buffer, *length);
15676 *len = *length;
15677 length = len;
15678 dst = buffer;
15679 }
15680
15681 /* execute and run text edit field */
15682 nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]);
15683 text_edit->active = (unsigned char)active;
15684 text_edit->string.len = *length;
15685 text_edit->cursor = NK_CLAMP(0, *cursor, *length);
15686 text_edit->string.buffer.allocated = (nk_size)*length;
15687 text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER;
15688 text_edit->string.buffer.memory.ptr = dst;
15689 text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER;
15690 text_edit->mode = NK_TEXT_EDIT_MODE_INSERT;
15691 nk_do_edit(ws, out, edit, NK_EDIT_ALWAYS_INSERT_MODE, filters[filter],
15692 text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font);
15693
15694 *length = text_edit->string.len;
15695 active = text_edit->active;
15696 *cursor = text_edit->cursor;
15697
15698 if (active && nk_input_is_key_pressed(in, NK_KEY_ENTER))
15699 active = !active;
15700
15701 if (old && !active) {
15702 /* property is now not active so convert edit text to value*/
15703 *state = NK_PROPERTY_DEFAULT;
15704 buffer[*len] = '\0';
15705 switch (variant->kind) {
15706 default: break;
15707 case NK_PROPERTY_INT:
15708 variant->value.i = nk_strtoi(buffer, 0);
15709 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
15710 break;
15711 case NK_PROPERTY_FLOAT:
15712 nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
15713 variant->value.f = nk_strtof(buffer, 0);
15714 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
15715 break;
15716 case NK_PROPERTY_DOUBLE:
15717 nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
15718 variant->value.d = nk_strtod(buffer, 0);
15719 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
15720 break;
15721 }
15722 }
15723}
15724/* ===============================================================
15725 *
15726 * COLOR PICKER
15727 *
15728 * ===============================================================*/
15729NK_INTERN int
15730nk_color_picker_behavior(nk_flags *state,
15731 const struct nk_rect *bounds, const struct nk_rect *matrix,
15732 const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,
15733 struct nk_color *color, const struct nk_input *in)
15734{
15735 float hsva[4];
15736 int value_changed = 0;
15737 int hsv_changed = 0;
15738
15739 NK_ASSERT(state);
15740 NK_ASSERT(matrix);
15741 NK_ASSERT(hue_bar);
15742 NK_ASSERT(color);
15743
15744 /* color matrix */
15745 nk_color_hsva_fv(hsva, *color);
15746 if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) {
15747 hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1));
15748 hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1));
15749 value_changed = hsv_changed = 1;
15750 }
15751
15752 /* hue bar */
15753 if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) {
15754 hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1));
15755 value_changed = hsv_changed = 1;
15756 }
15757
15758 /* alpha bar */
15759 if (alpha_bar) {
15760 if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) {
15761 hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1));
15762 value_changed = 1;
15763 }
15764 }
15765 nk_widget_state_reset(state);
15766 if (hsv_changed) {
15767 *color = nk_hsva_fv(hsva);
15768 *state = NK_WIDGET_STATE_ACTIVE;
15769 }
15770 if (value_changed) {
15771 color->a = (nk_byte)(hsva[3] * 255.0f);
15772 *state = NK_WIDGET_STATE_ACTIVE;
15773 }
15774
15775 /* set color picker widget state */
15776 if (nk_input_is_mouse_hovering_rect(in, *bounds))
15777 *state = NK_WIDGET_STATE_HOVERED;
15778 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds))
15779 *state |= NK_WIDGET_STATE_ENTERED;
15780 else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds))
15781 *state |= NK_WIDGET_STATE_LEFT;
15782 return value_changed;
15783}
15784
15785NK_INTERN void
15786nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix,
15787 const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,
15788 struct nk_color color)
15789{
15790 NK_STORAGE const struct nk_color black = {0,0,0,255};
15791 NK_STORAGE const struct nk_color white = {255, 255, 255, 255};
15792 NK_STORAGE const struct nk_color black_trans = {0,0,0,0};
15793
15794 const float crosshair_size = 7.0f;
15795 struct nk_color temp;
15796 float hsva[4];
15797 float line_y;
15798 int i;
15799
15800 NK_ASSERT(o);
15801 NK_ASSERT(matrix);
15802 NK_ASSERT(hue_bar);
15803
15804 /* draw hue bar */
15805 nk_color_hsv_fv(hsva, color);
15806 for (i = 0; i < 6; ++i) {
15807 NK_GLOBAL const struct nk_color hue_colors[] = {
15808 {255, 0, 0, 255},
15809 {255,255,0,255},
15810 {0,255,0,255},
15811 {0, 255,255,255},
15812 {0,0,255,255},
15813 {255, 0, 255, 255},
15814 {255, 0, 0, 255}
15815 };
15816 nk_fill_rect_multi_color(o,
15817 nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f,
15818 hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i],
15819 hue_colors[i+1], hue_colors[i+1]);
15820 }
15821 line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f);
15822 nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2,
15823 line_y, 1, nk_rgb(255,255,255));
15824
15825 /* draw alpha bar */
15826 if (alpha_bar) {
15827 float alpha = NK_SATURATE((float)color.a/255.0f);
15828 line_y = (float)(int)(alpha_bar->y + (1.0f - alpha) * matrix->h + 0.5f);
15829
15830 nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black);
15831 nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2,
15832 line_y, 1, nk_rgb(255,255,255));
15833 }
15834
15835 /* draw color matrix */
15836 temp = nk_hsv_f(hsva[0], 1.0f, 1.0f);
15837 nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white);
15838 nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black);
15839
15840 /* draw cross-hair */
15841 {struct nk_vec2 p; float S = hsva[1]; float V = hsva[2];
15842 p.x = (float)(int)(matrix->x + S * matrix->w);
15843 p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h);
15844 nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white);
15845 nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white);
15846 nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white);
15847 nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);}
15848}
15849
15850NK_INTERN int
15851nk_do_color_picker(nk_flags *state,
15852 struct nk_command_buffer *out, struct nk_color *color,
15853 enum nk_color_format fmt, struct nk_rect bounds,
15854 struct nk_vec2 padding, const struct nk_input *in,
15855 const struct nk_user_font *font)
15856{
15857 int ret = 0;
15858 struct nk_rect matrix;
15859 struct nk_rect hue_bar;
15860 struct nk_rect alpha_bar;
15861 float bar_w;
15862
15863 NK_ASSERT(out);
15864 NK_ASSERT(color);
15865 NK_ASSERT(state);
15866 NK_ASSERT(font);
15867 if (!out || !color || !state || !font)
15868 return ret;
15869
15870 bar_w = font->height;
15871 bounds.x += padding.x;
15872 bounds.y += padding.x;
15873 bounds.w -= 2 * padding.x;
15874 bounds.h -= 2 * padding.y;
15875
15876 matrix.x = bounds.x;
15877 matrix.y = bounds.y;
15878 matrix.h = bounds.h;
15879 matrix.w = bounds.w - (3 * padding.x + 2 * bar_w);
15880
15881 hue_bar.w = bar_w;
15882 hue_bar.y = bounds.y;
15883 hue_bar.h = matrix.h;
15884 hue_bar.x = matrix.x + matrix.w + padding.x;
15885
15886 alpha_bar.x = hue_bar.x + hue_bar.w + padding.x;
15887 alpha_bar.y = bounds.y;
15888 alpha_bar.w = bar_w;
15889 alpha_bar.h = matrix.h;
15890
15891 ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar,
15892 (fmt == NK_RGBA) ? &alpha_bar:0, color, in);
15893 nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *color);
15894 return ret;
15895}
15896
15897/* ==============================================================
15898 *
15899 * STYLE
15900 *
15901 * ===============================================================*/
15902NK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);}
15903#define NK_COLOR_MAP(NK_COLOR)\
15904 NK_COLOR(NK_COLOR_TEXT, 175,175,175,255) \
15905 NK_COLOR(NK_COLOR_WINDOW, 45, 45, 45, 255) \
15906 NK_COLOR(NK_COLOR_HEADER, 40, 40, 40, 255) \
15907 NK_COLOR(NK_COLOR_BORDER, 65, 65, 65, 255) \
15908 NK_COLOR(NK_COLOR_BUTTON, 50, 50, 50, 255) \
15909 NK_COLOR(NK_COLOR_BUTTON_HOVER, 40, 40, 40, 255) \
15910 NK_COLOR(NK_COLOR_BUTTON_ACTIVE, 35, 35, 35, 255) \
15911 NK_COLOR(NK_COLOR_TOGGLE, 100,100,100,255) \
15912 NK_COLOR(NK_COLOR_TOGGLE_HOVER, 120,120,120,255) \
15913 NK_COLOR(NK_COLOR_TOGGLE_CURSOR, 45, 45, 45, 255) \
15914 NK_COLOR(NK_COLOR_SELECT, 45, 45, 45, 255) \
15915 NK_COLOR(NK_COLOR_SELECT_ACTIVE, 35, 35, 35,255) \
15916 NK_COLOR(NK_COLOR_SLIDER, 38, 38, 38, 255) \
15917 NK_COLOR(NK_COLOR_SLIDER_CURSOR, 100,100,100,255) \
15918 NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER, 120,120,120,255) \
15919 NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE, 150,150,150,255) \
15920 NK_COLOR(NK_COLOR_PROPERTY, 38, 38, 38, 255) \
15921 NK_COLOR(NK_COLOR_EDIT, 38, 38, 38, 255) \
15922 NK_COLOR(NK_COLOR_EDIT_CURSOR, 175,175,175,255) \
15923 NK_COLOR(NK_COLOR_COMBO, 45, 45, 45, 255) \
15924 NK_COLOR(NK_COLOR_CHART, 120,120,120,255) \
15925 NK_COLOR(NK_COLOR_CHART_COLOR, 45, 45, 45, 255) \
15926 NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT,255, 0, 0, 255) \
15927 NK_COLOR(NK_COLOR_SCROLLBAR, 40, 40, 40, 255) \
15928 NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR, 100,100,100,255) \
15929 NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER,120,120,120,255) \
15930 NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,150,150,150,255) \
15931 NK_COLOR(NK_COLOR_TAB_HEADER, 40, 40, 40,255)
15932
15933NK_GLOBAL const struct nk_color
15934nk_default_color_style[NK_COLOR_COUNT] = {
15935#define NK_COLOR(a,b,c,d,e) {b,c,d,e},
15936 NK_COLOR_MAP(NK_COLOR)
15937#undef NK_COLOR
15938};
15939
15940NK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = {
15941#define NK_COLOR(a,b,c,d,e) #a,
15942 NK_COLOR_MAP(NK_COLOR)
15943#undef NK_COLOR
15944};
15945
15946NK_API const char *nk_style_get_color_by_name(enum nk_style_colors c)
15947{return nk_color_names[c];}
15948
15949NK_API struct nk_style_item nk_style_item_image(struct nk_image img)
15950{struct nk_style_item i; i.type = NK_STYLE_ITEM_IMAGE; i.data.image = img; return i;}
15951
15952NK_API struct nk_style_item nk_style_item_color(struct nk_color col)
15953{struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = col; return i;}
15954
15955NK_API struct nk_style_item nk_style_item_hide(void)
15956{struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = nk_rgba(0,0,0,0); return i;}
15957
15958NK_API void
15959nk_style_from_table(struct nk_context *ctx, const struct nk_color *table)
15960{
15961 struct nk_style *style;
15962 struct nk_style_text *text;
15963 struct nk_style_button *button;
15964 struct nk_style_toggle *toggle;
15965 struct nk_style_selectable *select;
15966 struct nk_style_slider *slider;
15967 struct nk_style_progress *prog;
15968 struct nk_style_scrollbar *scroll;
15969 struct nk_style_edit *edit;
15970 struct nk_style_property *property;
15971 struct nk_style_combo *combo;
15972 struct nk_style_chart *chart;
15973 struct nk_style_tab *tab;
15974 struct nk_style_window *win;
15975
15976 NK_ASSERT(ctx);
15977 if (!ctx) return;
15978 style = &ctx->style;
15979 table = (!table) ? nk_default_color_style: table;
15980
15981 /* default text */
15982 text = &style->text;
15983 text->color = table[NK_COLOR_TEXT];
15984 text->padding = nk_vec2(0,0);
15985
15986 /* default button */
15987 button = &style->button;
15988 nk_zero_struct(*button);
15989 button->normal = nk_style_item_color(table[NK_COLOR_BUTTON]);
15990 button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);
15991 button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);
15992 button->border_color = table[NK_COLOR_BORDER];
15993 button->text_background = table[NK_COLOR_BUTTON];
15994 button->text_normal = table[NK_COLOR_TEXT];
15995 button->text_hover = table[NK_COLOR_TEXT];
15996 button->text_active = table[NK_COLOR_TEXT];
15997 button->padding = nk_vec2(2.0f,2.0f);
15998 button->image_padding = nk_vec2(0.0f,0.0f);
15999 button->touch_padding = nk_vec2(0.0f, 0.0f);
16000 button->userdata = nk_handle_ptr(0);
16001 button->text_alignment = NK_TEXT_CENTERED;
16002 button->border = 1.0f;
16003 button->rounding = 4.0f;
16004 button->draw_begin = 0;
16005 button->draw_end = 0;
16006
16007 /* contextual button */
16008 button = &style->contextual_button;
16009 nk_zero_struct(*button);
16010 button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
16011 button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);
16012 button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);
16013 button->border_color = table[NK_COLOR_WINDOW];
16014 button->text_background = table[NK_COLOR_WINDOW];
16015 button->text_normal = table[NK_COLOR_TEXT];
16016 button->text_hover = table[NK_COLOR_TEXT];
16017 button->text_active = table[NK_COLOR_TEXT];
16018 button->padding = nk_vec2(2.0f,2.0f);
16019 button->touch_padding = nk_vec2(0.0f,0.0f);
16020 button->userdata = nk_handle_ptr(0);
16021 button->text_alignment = NK_TEXT_CENTERED;
16022 button->border = 0.0f;
16023 button->rounding = 0.0f;
16024 button->draw_begin = 0;
16025 button->draw_end = 0;
16026
16027 /* menu button */
16028 button = &style->menu_button;
16029 nk_zero_struct(*button);
16030 button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
16031 button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]);
16032 button->active = nk_style_item_color(table[NK_COLOR_WINDOW]);
16033 button->border_color = table[NK_COLOR_WINDOW];
16034 button->text_background = table[NK_COLOR_WINDOW];
16035 button->text_normal = table[NK_COLOR_TEXT];
16036 button->text_hover = table[NK_COLOR_TEXT];
16037 button->text_active = table[NK_COLOR_TEXT];
16038 button->padding = nk_vec2(2.0f,2.0f);
16039 button->touch_padding = nk_vec2(0.0f,0.0f);
16040 button->userdata = nk_handle_ptr(0);
16041 button->text_alignment = NK_TEXT_CENTERED;
16042 button->border = 0.0f;
16043 button->rounding = 1.0f;
16044 button->draw_begin = 0;
16045 button->draw_end = 0;
16046
16047 /* checkbox toggle */
16048 toggle = &style->checkbox;
16049 nk_zero_struct(*toggle);
16050 toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]);
16051 toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
16052 toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
16053 toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
16054 toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
16055 toggle->userdata = nk_handle_ptr(0);
16056 toggle->text_background = table[NK_COLOR_WINDOW];
16057 toggle->text_normal = table[NK_COLOR_TEXT];
16058 toggle->text_hover = table[NK_COLOR_TEXT];
16059 toggle->text_active = table[NK_COLOR_TEXT];
16060 toggle->padding = nk_vec2(2.0f, 2.0f);
16061 toggle->touch_padding = nk_vec2(0,0);
16062 toggle->border_color = nk_rgba(0,0,0,0);
16063 toggle->border = 0.0f;
16064 toggle->spacing = 4;
16065
16066 /* option toggle */
16067 toggle = &style->option;
16068 nk_zero_struct(*toggle);
16069 toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]);
16070 toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
16071 toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
16072 toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
16073 toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
16074 toggle->userdata = nk_handle_ptr(0);
16075 toggle->text_background = table[NK_COLOR_WINDOW];
16076 toggle->text_normal = table[NK_COLOR_TEXT];
16077 toggle->text_hover = table[NK_COLOR_TEXT];
16078 toggle->text_active = table[NK_COLOR_TEXT];
16079 toggle->padding = nk_vec2(3.0f, 3.0f);
16080 toggle->touch_padding = nk_vec2(0,0);
16081 toggle->border_color = nk_rgba(0,0,0,0);
16082 toggle->border = 0.0f;
16083 toggle->spacing = 4;
16084
16085 /* selectable */
16086 select = &style->selectable;
16087 nk_zero_struct(*select);
16088 select->normal = nk_style_item_color(table[NK_COLOR_SELECT]);
16089 select->hover = nk_style_item_color(table[NK_COLOR_SELECT]);
16090 select->pressed = nk_style_item_color(table[NK_COLOR_SELECT]);
16091 select->normal_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
16092 select->hover_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
16093 select->pressed_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
16094 select->text_normal = table[NK_COLOR_TEXT];
16095 select->text_hover = table[NK_COLOR_TEXT];
16096 select->text_pressed = table[NK_COLOR_TEXT];
16097 select->text_normal_active = table[NK_COLOR_TEXT];
16098 select->text_hover_active = table[NK_COLOR_TEXT];
16099 select->text_pressed_active = table[NK_COLOR_TEXT];
16100 select->padding = nk_vec2(2.0f,2.0f);
16101 select->touch_padding = nk_vec2(0,0);
16102 select->userdata = nk_handle_ptr(0);
16103 select->rounding = 0.0f;
16104 select->draw_begin = 0;
16105 select->draw_end = 0;
16106
16107 /* slider */
16108 slider = &style->slider;
16109 nk_zero_struct(*slider);
16110 slider->normal = nk_style_item_hide();
16111 slider->hover = nk_style_item_hide();
16112 slider->active = nk_style_item_hide();
16113 slider->bar_normal = table[NK_COLOR_SLIDER];
16114 slider->bar_hover = table[NK_COLOR_SLIDER];
16115 slider->bar_active = table[NK_COLOR_SLIDER];
16116 slider->bar_filled = table[NK_COLOR_SLIDER_CURSOR];
16117 slider->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);
16118 slider->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);
16119 slider->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);
16120 slider->inc_symbol = NK_SYMBOL_TRIANGLE_RIGHT;
16121 slider->dec_symbol = NK_SYMBOL_TRIANGLE_LEFT;
16122 slider->cursor_size = nk_vec2(16,16);
16123 slider->padding = nk_vec2(2,2);
16124 slider->spacing = nk_vec2(2,2);
16125 slider->userdata = nk_handle_ptr(0);
16126 slider->show_buttons = nk_false;
16127 slider->bar_height = 8;
16128 slider->rounding = 0;
16129 slider->draw_begin = 0;
16130 slider->draw_end = 0;
16131
16132 /* slider buttons */
16133 button = &style->slider.inc_button;
16134 button->normal = nk_style_item_color(nk_rgb(40,40,40));
16135 button->hover = nk_style_item_color(nk_rgb(42,42,42));
16136 button->active = nk_style_item_color(nk_rgb(44,44,44));
16137 button->border_color = nk_rgb(65,65,65);
16138 button->text_background = nk_rgb(40,40,40);
16139 button->text_normal = nk_rgb(175,175,175);
16140 button->text_hover = nk_rgb(175,175,175);
16141 button->text_active = nk_rgb(175,175,175);
16142 button->padding = nk_vec2(8.0f,8.0f);
16143 button->touch_padding = nk_vec2(0.0f,0.0f);
16144 button->userdata = nk_handle_ptr(0);
16145 button->text_alignment = NK_TEXT_CENTERED;
16146 button->border = 1.0f;
16147 button->rounding = 0.0f;
16148 button->draw_begin = 0;
16149 button->draw_end = 0;
16150 style->slider.dec_button = style->slider.inc_button;
16151
16152 /* progressbar */
16153 prog = &style->progress;
16154 nk_zero_struct(*prog);
16155 prog->normal = nk_style_item_color(table[NK_COLOR_SLIDER]);
16156 prog->hover = nk_style_item_color(table[NK_COLOR_SLIDER]);
16157 prog->active = nk_style_item_color(table[NK_COLOR_SLIDER]);
16158 prog->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);
16159 prog->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);
16160 prog->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);
16161 prog->border_color = nk_rgba(0,0,0,0);
16162 prog->cursor_border_color = nk_rgba(0,0,0,0);
16163 prog->userdata = nk_handle_ptr(0);
16164 prog->padding = nk_vec2(4,4);
16165 prog->rounding = 0;
16166 prog->border = 0;
16167 prog->cursor_rounding = 0;
16168 prog->cursor_border = 0;
16169 prog->draw_begin = 0;
16170 prog->draw_end = 0;
16171
16172 /* scrollbars */
16173 scroll = &style->scrollh;
16174 nk_zero_struct(*scroll);
16175 scroll->normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
16176 scroll->hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
16177 scroll->active = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
16178 scroll->cursor_normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]);
16179 scroll->cursor_hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]);
16180 scroll->cursor_active = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]);
16181 scroll->dec_symbol = NK_SYMBOL_CIRCLE_SOLID;
16182 scroll->inc_symbol = NK_SYMBOL_CIRCLE_SOLID;
16183 scroll->userdata = nk_handle_ptr(0);
16184 scroll->border_color = table[NK_COLOR_SCROLLBAR];
16185 scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR];
16186 scroll->padding = nk_vec2(0,0);
16187 scroll->show_buttons = nk_false;
16188 scroll->border = 0;
16189 scroll->rounding = 0;
16190 scroll->border_cursor = 0;
16191 scroll->rounding_cursor = 0;
16192 scroll->draw_begin = 0;
16193 scroll->draw_end = 0;
16194 style->scrollv = style->scrollh;
16195
16196 /* scrollbars buttons */
16197 button = &style->scrollh.inc_button;
16198 button->normal = nk_style_item_color(nk_rgb(40,40,40));
16199 button->hover = nk_style_item_color(nk_rgb(42,42,42));
16200 button->active = nk_style_item_color(nk_rgb(44,44,44));
16201 button->border_color = nk_rgb(65,65,65);
16202 button->text_background = nk_rgb(40,40,40);
16203 button->text_normal = nk_rgb(175,175,175);
16204 button->text_hover = nk_rgb(175,175,175);
16205 button->text_active = nk_rgb(175,175,175);
16206 button->padding = nk_vec2(4.0f,4.0f);
16207 button->touch_padding = nk_vec2(0.0f,0.0f);
16208 button->userdata = nk_handle_ptr(0);
16209 button->text_alignment = NK_TEXT_CENTERED;
16210 button->border = 1.0f;
16211 button->rounding = 0.0f;
16212 button->draw_begin = 0;
16213 button->draw_end = 0;
16214 style->scrollh.dec_button = style->scrollh.inc_button;
16215 style->scrollv.inc_button = style->scrollh.inc_button;
16216 style->scrollv.dec_button = style->scrollh.inc_button;
16217
16218 /* edit */
16219 edit = &style->edit;
16220 nk_zero_struct(*edit);
16221 edit->normal = nk_style_item_color(table[NK_COLOR_EDIT]);
16222 edit->hover = nk_style_item_color(table[NK_COLOR_EDIT]);
16223 edit->active = nk_style_item_color(table[NK_COLOR_EDIT]);
16224 edit->cursor_normal = table[NK_COLOR_TEXT];
16225 edit->cursor_hover = table[NK_COLOR_TEXT];
16226 edit->cursor_text_normal= table[NK_COLOR_EDIT];
16227 edit->cursor_text_hover = table[NK_COLOR_EDIT];
16228 edit->border_color = table[NK_COLOR_BORDER];
16229 edit->text_normal = table[NK_COLOR_TEXT];
16230 edit->text_hover = table[NK_COLOR_TEXT];
16231 edit->text_active = table[NK_COLOR_TEXT];
16232 edit->selected_normal = table[NK_COLOR_TEXT];
16233 edit->selected_hover = table[NK_COLOR_TEXT];
16234 edit->selected_text_normal = table[NK_COLOR_EDIT];
16235 edit->selected_text_hover = table[NK_COLOR_EDIT];
16236 edit->scrollbar_size = nk_vec2(10,10);
16237 edit->scrollbar = style->scrollv;
16238 edit->padding = nk_vec2(4,4);
16239 edit->row_padding = 2;
16240 edit->cursor_size = 4;
16241 edit->border = 1;
16242 edit->rounding = 0;
16243
16244 /* property */
16245 property = &style->property;
16246 nk_zero_struct(*property);
16247 property->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16248 property->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16249 property->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16250 property->border_color = table[NK_COLOR_BORDER];
16251 property->label_normal = table[NK_COLOR_TEXT];
16252 property->label_hover = table[NK_COLOR_TEXT];
16253 property->label_active = table[NK_COLOR_TEXT];
16254 property->sym_left = NK_SYMBOL_TRIANGLE_LEFT;
16255 property->sym_right = NK_SYMBOL_TRIANGLE_RIGHT;
16256 property->userdata = nk_handle_ptr(0);
16257 property->padding = nk_vec2(4,4);
16258 property->border = 1;
16259 property->rounding = 10;
16260 property->draw_begin = 0;
16261 property->draw_end = 0;
16262
16263 /* property buttons */
16264 button = &style->property.dec_button;
16265 nk_zero_struct(*button);
16266 button->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16267 button->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16268 button->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16269 button->border_color = nk_rgba(0,0,0,0);
16270 button->text_background = table[NK_COLOR_PROPERTY];
16271 button->text_normal = table[NK_COLOR_TEXT];
16272 button->text_hover = table[NK_COLOR_TEXT];
16273 button->text_active = table[NK_COLOR_TEXT];
16274 button->padding = nk_vec2(0.0f,0.0f);
16275 button->touch_padding = nk_vec2(0.0f,0.0f);
16276 button->userdata = nk_handle_ptr(0);
16277 button->text_alignment = NK_TEXT_CENTERED;
16278 button->border = 0.0f;
16279 button->rounding = 0.0f;
16280 button->draw_begin = 0;
16281 button->draw_end = 0;
16282 style->property.inc_button = style->property.dec_button;
16283
16284 /* property edit */
16285 edit = &style->property.edit;
16286 nk_zero_struct(*edit);
16287 edit->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16288 edit->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16289 edit->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16290 edit->border_color = nk_rgba(0,0,0,0);
16291 edit->cursor_normal = table[NK_COLOR_TEXT];
16292 edit->cursor_hover = table[NK_COLOR_TEXT];
16293 edit->cursor_text_normal= table[NK_COLOR_EDIT];
16294 edit->cursor_text_hover = table[NK_COLOR_EDIT];
16295 edit->text_normal = table[NK_COLOR_TEXT];
16296 edit->text_hover = table[NK_COLOR_TEXT];
16297 edit->text_active = table[NK_COLOR_TEXT];
16298 edit->selected_normal = table[NK_COLOR_TEXT];
16299 edit->selected_hover = table[NK_COLOR_TEXT];
16300 edit->selected_text_normal = table[NK_COLOR_EDIT];
16301 edit->selected_text_hover = table[NK_COLOR_EDIT];
16302 edit->padding = nk_vec2(0,0);
16303 edit->cursor_size = 8;
16304 edit->border = 0;
16305 edit->rounding = 0;
16306
16307 /* chart */
16308 chart = &style->chart;
16309 nk_zero_struct(*chart);
16310 chart->background = nk_style_item_color(table[NK_COLOR_CHART]);
16311 chart->border_color = table[NK_COLOR_BORDER];
16312 chart->selected_color = table[NK_COLOR_CHART_COLOR_HIGHLIGHT];
16313 chart->color = table[NK_COLOR_CHART_COLOR];
16314 chart->padding = nk_vec2(4,4);
16315 chart->border = 0;
16316 chart->rounding = 0;
16317
16318 /* combo */
16319 combo = &style->combo;
16320 combo->normal = nk_style_item_color(table[NK_COLOR_COMBO]);
16321 combo->hover = nk_style_item_color(table[NK_COLOR_COMBO]);
16322 combo->active = nk_style_item_color(table[NK_COLOR_COMBO]);
16323 combo->border_color = table[NK_COLOR_BORDER];
16324 combo->label_normal = table[NK_COLOR_TEXT];
16325 combo->label_hover = table[NK_COLOR_TEXT];
16326 combo->label_active = table[NK_COLOR_TEXT];
16327 combo->sym_normal = NK_SYMBOL_TRIANGLE_DOWN;
16328 combo->sym_hover = NK_SYMBOL_TRIANGLE_DOWN;
16329 combo->sym_active = NK_SYMBOL_TRIANGLE_DOWN;
16330 combo->content_padding = nk_vec2(4,4);
16331 combo->button_padding = nk_vec2(0,4);
16332 combo->spacing = nk_vec2(4,0);
16333 combo->border = 1;
16334 combo->rounding = 0;
16335
16336 /* combo button */
16337 button = &style->combo.button;
16338 nk_zero_struct(*button);
16339 button->normal = nk_style_item_color(table[NK_COLOR_COMBO]);
16340 button->hover = nk_style_item_color(table[NK_COLOR_COMBO]);
16341 button->active = nk_style_item_color(table[NK_COLOR_COMBO]);
16342 button->border_color = nk_rgba(0,0,0,0);
16343 button->text_background = table[NK_COLOR_COMBO];
16344 button->text_normal = table[NK_COLOR_TEXT];
16345 button->text_hover = table[NK_COLOR_TEXT];
16346 button->text_active = table[NK_COLOR_TEXT];
16347 button->padding = nk_vec2(2.0f,2.0f);
16348 button->touch_padding = nk_vec2(0.0f,0.0f);
16349 button->userdata = nk_handle_ptr(0);
16350 button->text_alignment = NK_TEXT_CENTERED;
16351 button->border = 0.0f;
16352 button->rounding = 0.0f;
16353 button->draw_begin = 0;
16354 button->draw_end = 0;
16355
16356 /* tab */
16357 tab = &style->tab;
16358 tab->background = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
16359 tab->border_color = table[NK_COLOR_BORDER];
16360 tab->text = table[NK_COLOR_TEXT];
16361 tab->sym_minimize = NK_SYMBOL_TRIANGLE_RIGHT;
16362 tab->sym_maximize = NK_SYMBOL_TRIANGLE_DOWN;
16363 tab->padding = nk_vec2(4,4);
16364 tab->spacing = nk_vec2(4,4);
16365 tab->indent = 10.0f;
16366 tab->border = 1;
16367 tab->rounding = 0;
16368
16369 /* tab button */
16370 button = &style->tab.tab_minimize_button;
16371 nk_zero_struct(*button);
16372 button->normal = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
16373 button->hover = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
16374 button->active = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
16375 button->border_color = nk_rgba(0,0,0,0);
16376 button->text_background = table[NK_COLOR_TAB_HEADER];
16377 button->text_normal = table[NK_COLOR_TEXT];
16378 button->text_hover = table[NK_COLOR_TEXT];
16379 button->text_active = table[NK_COLOR_TEXT];
16380 button->padding = nk_vec2(2.0f,2.0f);
16381 button->touch_padding = nk_vec2(0.0f,0.0f);
16382 button->userdata = nk_handle_ptr(0);
16383 button->text_alignment = NK_TEXT_CENTERED;
16384 button->border = 0.0f;
16385 button->rounding = 0.0f;
16386 button->draw_begin = 0;
16387 button->draw_end = 0;
16388 style->tab.tab_maximize_button =*button;
16389
16390 /* node button */
16391 button = &style->tab.node_minimize_button;
16392 nk_zero_struct(*button);
16393 button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
16394 button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]);
16395 button->active = nk_style_item_color(table[NK_COLOR_WINDOW]);
16396 button->border_color = nk_rgba(0,0,0,0);
16397 button->text_background = table[NK_COLOR_TAB_HEADER];
16398 button->text_normal = table[NK_COLOR_TEXT];
16399 button->text_hover = table[NK_COLOR_TEXT];
16400 button->text_active = table[NK_COLOR_TEXT];
16401 button->padding = nk_vec2(2.0f,2.0f);
16402 button->touch_padding = nk_vec2(0.0f,0.0f);
16403 button->userdata = nk_handle_ptr(0);
16404 button->text_alignment = NK_TEXT_CENTERED;
16405 button->border = 0.0f;
16406 button->rounding = 0.0f;
16407 button->draw_begin = 0;
16408 button->draw_end = 0;
16409 style->tab.node_maximize_button =*button;
16410
16411 /* window header */
16412 win = &style->window;
16413 win->header.align = NK_HEADER_RIGHT;
16414 win->header.close_symbol = NK_SYMBOL_X;
16415 win->header.minimize_symbol = NK_SYMBOL_MINUS;
16416 win->header.maximize_symbol = NK_SYMBOL_PLUS;
16417 win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]);
16418 win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]);
16419 win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]);
16420 win->header.label_normal = table[NK_COLOR_TEXT];
16421 win->header.label_hover = table[NK_COLOR_TEXT];
16422 win->header.label_active = table[NK_COLOR_TEXT];
16423 win->header.label_padding = nk_vec2(4,4);
16424 win->header.padding = nk_vec2(4,4);
16425 win->header.spacing = nk_vec2(0,0);
16426
16427 /* window header close button */
16428 button = &style->window.header.close_button;
16429 nk_zero_struct(*button);
16430 button->normal = nk_style_item_color(table[NK_COLOR_HEADER]);
16431 button->hover = nk_style_item_color(table[NK_COLOR_HEADER]);
16432 button->active = nk_style_item_color(table[NK_COLOR_HEADER]);
16433 button->border_color = nk_rgba(0,0,0,0);
16434 button->text_background = table[NK_COLOR_HEADER];
16435 button->text_normal = table[NK_COLOR_TEXT];
16436 button->text_hover = table[NK_COLOR_TEXT];
16437 button->text_active = table[NK_COLOR_TEXT];
16438 button->padding = nk_vec2(0.0f,0.0f);
16439 button->touch_padding = nk_vec2(0.0f,0.0f);
16440 button->userdata = nk_handle_ptr(0);
16441 button->text_alignment = NK_TEXT_CENTERED;
16442 button->border = 0.0f;
16443 button->rounding = 0.0f;
16444 button->draw_begin = 0;
16445 button->draw_end = 0;
16446
16447 /* window header minimize button */
16448 button = &style->window.header.minimize_button;
16449 nk_zero_struct(*button);
16450 button->normal = nk_style_item_color(table[NK_COLOR_HEADER]);
16451 button->hover = nk_style_item_color(table[NK_COLOR_HEADER]);
16452 button->active = nk_style_item_color(table[NK_COLOR_HEADER]);
16453 button->border_color = nk_rgba(0,0,0,0);
16454 button->text_background = table[NK_COLOR_HEADER];
16455 button->text_normal = table[NK_COLOR_TEXT];
16456 button->text_hover = table[NK_COLOR_TEXT];
16457 button->text_active = table[NK_COLOR_TEXT];
16458 button->padding = nk_vec2(0.0f,0.0f);
16459 button->touch_padding = nk_vec2(0.0f,0.0f);
16460 button->userdata = nk_handle_ptr(0);
16461 button->text_alignment = NK_TEXT_CENTERED;
16462 button->border = 0.0f;
16463 button->rounding = 0.0f;
16464 button->draw_begin = 0;
16465 button->draw_end = 0;
16466
16467 /* window */
16468 win->background = table[NK_COLOR_WINDOW];
16469 win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]);
16470 win->border_color = table[NK_COLOR_BORDER];
16471 win->popup_border_color = table[NK_COLOR_BORDER];
16472 win->combo_border_color = table[NK_COLOR_BORDER];
16473 win->contextual_border_color = table[NK_COLOR_BORDER];
16474 win->menu_border_color = table[NK_COLOR_BORDER];
16475 win->group_border_color = table[NK_COLOR_BORDER];
16476 win->tooltip_border_color = table[NK_COLOR_BORDER];
16477 win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]);
16478
16479 win->rounding = 0.0f;
16480 win->spacing = nk_vec2(4,4);
16481 win->scrollbar_size = nk_vec2(10,10);
16482 win->min_size = nk_vec2(64,64);
16483
16484 win->combo_border = 1.0f;
16485 win->contextual_border = 1.0f;
16486 win->menu_border = 1.0f;
16487 win->group_border = 1.0f;
16488 win->tooltip_border = 1.0f;
16489 win->popup_border = 1.0f;
16490 win->border = 2.0f;
16491
16492 win->padding = nk_vec2(4,4);
16493 win->group_padding = nk_vec2(4,4);
16494 win->popup_padding = nk_vec2(4,4);
16495 win->combo_padding = nk_vec2(4,4);
16496 win->contextual_padding = nk_vec2(4,4);
16497 win->menu_padding = nk_vec2(4,4);
16498 win->tooltip_padding = nk_vec2(4,4);
16499}
16500
16501NK_API void
16502nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font)
16503{
16504 struct nk_style *style;
16505 NK_ASSERT(ctx);
16506 if (!ctx) return;
16507 style = &ctx->style;
16508 style->font = font;
16509 ctx->stacks.fonts.head = 0;
16510}
16511
16512NK_API int
16513nk_style_push_font(struct nk_context *ctx, struct nk_user_font *font)
16514{
16515 struct nk_config_stack_user_font *font_stack;
16516 struct nk_config_stack_user_font_element *element;
16517
16518 NK_ASSERT(ctx);
16519 if (!ctx) return 0;
16520
16521 font_stack = &ctx->stacks.fonts;
16522 NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements));
16523 if (font_stack->head >= (int)NK_LEN(font_stack->elements))
16524 return 0;
16525
16526 element = &font_stack->elements[font_stack->head++];
16527 element->address = &ctx->style.font;
16528 element->old_value = ctx->style.font;
16529 ctx->style.font = font;
16530 return 1;
16531}
16532
16533NK_API int
16534nk_style_pop_font(struct nk_context *ctx)
16535{
16536 struct nk_config_stack_user_font *font_stack;
16537 struct nk_config_stack_user_font_element *element;
16538
16539 NK_ASSERT(ctx);
16540 if (!ctx) return 0;
16541
16542 font_stack = &ctx->stacks.fonts;
16543 NK_ASSERT(font_stack->head > 0);
16544 if (font_stack->head < 1)
16545 return 0;
16546
16547 element = &font_stack->elements[--font_stack->head];
16548 *element->address = element->old_value;
16549 return 1;
16550}
16551
16552#define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \
16553nk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\
16554{\
16555 struct nk_config_stack_##type * type_stack;\
16556 struct nk_config_stack_##type##_element *element;\
16557 NK_ASSERT(ctx);\
16558 if (!ctx) return 0;\
16559 type_stack = &ctx->stacks.stack;\
16560 NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\
16561 if (type_stack->head >= (int)NK_LEN(type_stack->elements))\
16562 return 0;\
16563 element = &type_stack->elements[type_stack->head++];\
16564 element->address = address;\
16565 element->old_value = *address;\
16566 *address = value;\
16567 return 1;\
16568}
16569
16570#define NK_STYLE_POP_IMPLEMENATION(type, stack) \
16571nk_style_pop_##type(struct nk_context *ctx)\
16572{\
16573 struct nk_config_stack_##type *type_stack;\
16574 struct nk_config_stack_##type##_element *element;\
16575 NK_ASSERT(ctx);\
16576 if (!ctx) return 0;\
16577 type_stack = &ctx->stacks.stack;\
16578 NK_ASSERT(type_stack->head > 0);\
16579 if (type_stack->head < 1)\
16580 return 0;\
16581 element = &type_stack->elements[--type_stack->head];\
16582 *element->address = element->old_value;\
16583 return 1;\
16584}
16585
16586NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items)
16587NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats)
16588NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors)
16589NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags)
16590NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors)
16591
16592NK_API int NK_STYLE_POP_IMPLEMENATION(style_item, style_items)
16593NK_API int NK_STYLE_POP_IMPLEMENATION(float,floats)
16594NK_API int NK_STYLE_POP_IMPLEMENATION(vec2, vectors)
16595NK_API int NK_STYLE_POP_IMPLEMENATION(flags,flags)
16596NK_API int NK_STYLE_POP_IMPLEMENATION(color,colors)
16597
16598NK_API int
16599nk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c)
16600{
16601 struct nk_style *style;
16602 NK_ASSERT(ctx);
16603 if (!ctx) return 0;
16604 style = &ctx->style;
16605 if (style->cursors[c]) {
16606 style->cursor_active = style->cursors[c];
16607 return 1;
16608 }
16609 return 0;
16610}
16611
16612NK_API void
16613nk_style_show_cursor(struct nk_context *ctx)
16614{
16615 ctx->style.cursor_visible = nk_true;
16616}
16617
16618NK_API void
16619nk_style_hide_cursor(struct nk_context *ctx)
16620{
16621 ctx->style.cursor_visible = nk_false;
16622}
16623
16624NK_API void
16625nk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor,
16626 const struct nk_cursor *c)
16627{
16628 struct nk_style *style;
16629 NK_ASSERT(ctx);
16630 if (!ctx) return;
16631 style = &ctx->style;
16632 style->cursors[cursor] = c;
16633}
16634
16635NK_API void
16636nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors)
16637{
16638 int i = 0;
16639 struct nk_style *style;
16640 NK_ASSERT(ctx);
16641 if (!ctx) return;
16642 style = &ctx->style;
16643 for (i = 0; i < NK_CURSOR_COUNT; ++i)
16644 style->cursors[i] = &cursors[i];
16645 style->cursor_visible = nk_true;
16646}
16647
16648/* ===============================================================
16649 *
16650 * POOL
16651 *
16652 * ===============================================================*/
16653NK_INTERN void
16654nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc,
16655 unsigned int capacity)
16656{
16657 nk_zero(pool, sizeof(*pool));
16658 pool->alloc = *alloc;
16659 pool->capacity = capacity;
16660 pool->type = NK_BUFFER_DYNAMIC;
16661 pool->pages = 0;
16662}
16663
16664NK_INTERN void
16665nk_pool_free(struct nk_pool *pool)
16666{
16667 struct nk_page *iter = pool->pages;
16668 if (!pool) return;
16669 if (pool->type == NK_BUFFER_FIXED) return;
16670 while (iter) {
16671 struct nk_page *next = iter->next;
16672 pool->alloc.free(pool->alloc.userdata, iter);
16673 iter = next;
16674 }
16675}
16676
16677NK_INTERN void
16678nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size)
16679{
16680 nk_zero(pool, sizeof(*pool));
16681 NK_ASSERT(size >= sizeof(struct nk_page));
16682 if (size < sizeof(struct nk_page)) return;
16683 pool->capacity = (unsigned)(size - sizeof(struct nk_page)) / sizeof(struct nk_page_element);
16684 pool->pages = (struct nk_page*)memory;
16685 pool->type = NK_BUFFER_FIXED;
16686 pool->size = size;
16687}
16688
16689NK_INTERN struct nk_page_element*
16690nk_pool_alloc(struct nk_pool *pool)
16691{
16692 if (!pool->pages || pool->pages->size >= pool->capacity) {
16693 /* allocate new page */
16694 struct nk_page *page;
16695 if (pool->type == NK_BUFFER_FIXED) {
16696 if (!pool->pages) {
16697 NK_ASSERT(pool->pages);
16698 return 0;
16699 }
16700 NK_ASSERT(pool->pages->size < pool->capacity);
16701 return 0;
16702 } else {
16703 nk_size size = sizeof(struct nk_page);
16704 size += NK_POOL_DEFAULT_CAPACITY * sizeof(union nk_page_data);
16705 page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size);
16706 page->next = pool->pages;
16707 pool->pages = page;
16708 page->size = 0;
16709 }
16710 }
16711 return &pool->pages->win[pool->pages->size++];
16712}
16713
16714/* ===============================================================
16715 *
16716 * CONTEXT
16717 *
16718 * ===============================================================*/
16719NK_INTERN void* nk_create_window(struct nk_context *ctx);
16720NK_INTERN void nk_remove_window(struct nk_context*, struct nk_window*);
16721NK_INTERN void nk_free_window(struct nk_context *ctx, struct nk_window *win);
16722NK_INTERN void nk_free_table(struct nk_context *ctx, struct nk_table *tbl);
16723NK_INTERN void nk_remove_table(struct nk_window *win, struct nk_table *tbl);
16724NK_INTERN void* nk_create_panel(struct nk_context *ctx);
16725NK_INTERN void nk_free_panel(struct nk_context*, struct nk_panel *pan);
16726
16727NK_INTERN void
16728nk_setup(struct nk_context *ctx, const struct nk_user_font *font)
16729{
16730 NK_ASSERT(ctx);
16731 if (!ctx) return;
16732 nk_zero_struct(*ctx);
16733 nk_style_default(ctx);
16734 ctx->seq = 1;
16735 if (font) ctx->style.font = font;
16736#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
16737 nk_draw_list_init(&ctx->draw_list);
16738#endif
16739}
16740
16741#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
16742NK_API int
16743nk_init_default(struct nk_context *ctx, const struct nk_user_font *font)
16744{
16745 struct nk_allocator alloc;
16746 alloc.userdata.ptr = 0;
16747 alloc.alloc = nk_malloc;
16748 alloc.free = nk_mfree;
16749 return nk_init(ctx, &alloc, font);
16750}
16751#endif
16752
16753NK_API int
16754nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size,
16755 const struct nk_user_font *font)
16756{
16757 NK_ASSERT(memory);
16758 if (!memory) return 0;
16759 nk_setup(ctx, font);
16760 nk_buffer_init_fixed(&ctx->memory, memory, size);
16761 ctx->use_pool = nk_false;
16762 return 1;
16763}
16764
16765NK_API int
16766nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds,
16767 struct nk_buffer *pool, const struct nk_user_font *font)
16768{
16769 NK_ASSERT(cmds);
16770 NK_ASSERT(pool);
16771 if (!cmds || !pool) return 0;
16772
16773 nk_setup(ctx, font);
16774 ctx->memory = *cmds;
16775 if (pool->type == NK_BUFFER_FIXED) {
16776 /* take memory from buffer and alloc fixed pool */
16777 nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size);
16778 } else {
16779 /* create dynamic pool from buffer allocator */
16780 struct nk_allocator *alloc = &pool->pool;
16781 nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
16782 }
16783 ctx->use_pool = nk_true;
16784 return 1;
16785}
16786
16787NK_API int
16788nk_init(struct nk_context *ctx, struct nk_allocator *alloc,
16789 const struct nk_user_font *font)
16790{
16791 NK_ASSERT(alloc);
16792 if (!alloc) return 0;
16793 nk_setup(ctx, font);
16794 nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE);
16795 nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
16796 ctx->use_pool = nk_true;
16797 return 1;
16798}
16799
16800#ifdef NK_INCLUDE_COMMAND_USERDATA
16801NK_API void
16802nk_set_user_data(struct nk_context *ctx, nk_handle handle)
16803{
16804 if (!ctx) return;
16805 ctx->userdata = handle;
16806 if (ctx->current)
16807 ctx->current->buffer.userdata = handle;
16808}
16809#endif
16810
16811NK_API void
16812nk_free(struct nk_context *ctx)
16813{
16814 NK_ASSERT(ctx);
16815 if (!ctx) return;
16816 nk_buffer_free(&ctx->memory);
16817 if (ctx->use_pool)
16818 nk_pool_free(&ctx->pool);
16819
16820 nk_zero(&ctx->input, sizeof(ctx->input));
16821 nk_zero(&ctx->style, sizeof(ctx->style));
16822 nk_zero(&ctx->memory, sizeof(ctx->memory));
16823
16824 ctx->seq = 0;
16825 ctx->build = 0;
16826 ctx->begin = 0;
16827 ctx->end = 0;
16828 ctx->active = 0;
16829 ctx->current = 0;
16830 ctx->freelist = 0;
16831 ctx->count = 0;
16832}
16833
16834NK_API void
16835nk_clear(struct nk_context *ctx)
16836{
16837 struct nk_window *iter;
16838 struct nk_window *next;
16839 NK_ASSERT(ctx);
16840
16841 if (!ctx) return;
16842 if (ctx->use_pool)
16843 nk_buffer_clear(&ctx->memory);
16844 else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT);
16845
16846 ctx->build = 0;
16847 ctx->memory.calls = 0;
16848 ctx->last_widget_state = 0;
16849 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
16850 NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay));
16851#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
16852 nk_draw_list_clear(&ctx->draw_list);
16853#endif
16854
16855 /* garbage collector */
16856 iter = ctx->begin;
16857 while (iter) {
16858 /* make sure minimized windows do not get removed */
16859 if ((iter->flags & NK_WINDOW_MINIMIZED) &&
16860 !(iter->flags & NK_WINDOW_CLOSED)) {
16861 iter = iter->next;
16862 continue;
16863 }
16864
16865 /* remove hotness from hidden or closed windows*/
16866 if (((iter->flags & NK_WINDOW_HIDDEN) ||
16867 (iter->flags & NK_WINDOW_CLOSED)) &&
16868 iter == ctx->active)
16869 ctx->active = iter->next;
16870
16871 /* free unused popup windows */
16872 if (iter->popup.win && iter->popup.win->seq != ctx->seq) {
16873 nk_free_window(ctx, iter->popup.win);
16874 iter->popup.win = 0;
16875 }
16876
16877 /* remove unused window state tables */
16878 {struct nk_table *n, *it = iter->tables;
16879 while (it) {
16880 n = it->next;
16881 if (it->seq != ctx->seq) {
16882 nk_remove_table(iter, it);
16883 nk_zero(it, sizeof(union nk_page_data));
16884 nk_free_table(ctx, it);
16885 if (it == iter->tables)
16886 iter->tables = n;
16887 }
16888 it = n;
16889 }}
16890
16891 /* window itself is not used anymore so free */
16892 if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {
16893 next = iter->next;
16894 nk_remove_window(ctx, iter);
16895 nk_free_window(ctx, iter);
16896 iter = next;
16897 } else iter = iter->next;
16898 }
16899 ctx->seq++;
16900}
16901
16902/* ----------------------------------------------------------------
16903 *
16904 * BUFFERING
16905 *
16906 * ---------------------------------------------------------------*/
16907NK_INTERN void
16908nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
16909{
16910 NK_ASSERT(ctx);
16911 NK_ASSERT(buffer);
16912 if (!ctx || !buffer) return;
16913 buffer->begin = ctx->memory.allocated;
16914 buffer->end = buffer->begin;
16915 buffer->last = buffer->begin;
16916 buffer->clip = nk_null_rect;
16917}
16918
16919NK_INTERN void
16920nk_start(struct nk_context *ctx, struct nk_window *win)
16921{
16922 NK_ASSERT(ctx);
16923 NK_ASSERT(win);
16924 nk_start_buffer(ctx, &win->buffer);
16925}
16926
16927NK_INTERN void
16928nk_start_popup(struct nk_context *ctx, struct nk_window *win)
16929{
16930 struct nk_popup_buffer *buf;
16931 NK_ASSERT(ctx);
16932 NK_ASSERT(win);
16933 if (!ctx || !win) return;
16934
16935 /* save buffer fill state for popup */
16936 buf = &win->popup.buf;
16937 buf->begin = win->buffer.end;
16938 buf->end = win->buffer.end;
16939 buf->parent = win->buffer.last;
16940 buf->last = buf->begin;
16941 buf->active = nk_true;
16942}
16943
16944NK_INTERN void
16945nk_finish_popup(struct nk_context *ctx, struct nk_window *win)
16946{
16947 struct nk_popup_buffer *buf;
16948 NK_ASSERT(ctx);
16949 NK_ASSERT(win);
16950 if (!ctx || !win) return;
16951
16952 buf = &win->popup.buf;
16953 buf->last = win->buffer.last;
16954 buf->end = win->buffer.end;
16955}
16956
16957NK_INTERN void
16958nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
16959{
16960 NK_ASSERT(ctx);
16961 NK_ASSERT(buffer);
16962 if (!ctx || !buffer) return;
16963 buffer->end = ctx->memory.allocated;
16964}
16965
16966NK_INTERN void
16967nk_finish(struct nk_context *ctx, struct nk_window *win)
16968{
16969 struct nk_popup_buffer *buf;
16970 struct nk_command *parent_last;
16971 void *memory;
16972
16973 NK_ASSERT(ctx);
16974 NK_ASSERT(win);
16975 if (!ctx || !win) return;
16976 nk_finish_buffer(ctx, &win->buffer);
16977 if (!win->popup.buf.active) return;
16978
16979 buf = &win->popup.buf;
16980 memory = ctx->memory.memory.ptr;
16981 parent_last = nk_ptr_add(struct nk_command, memory, buf->parent);
16982 parent_last->next = buf->end;
16983}
16984
16985NK_INTERN void
16986nk_build(struct nk_context *ctx)
16987{
16988 struct nk_window *iter = 0;
16989 struct nk_command *cmd = 0;
16990 nk_byte *buffer = 0;
16991
16992 /* draw cursor overlay */
16993 if (!ctx->style.cursor_active)
16994 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
16995 if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) {
16996 struct nk_rect mouse_bounds;
16997 const struct nk_cursor *cursor = ctx->style.cursor_active;
16998 nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF);
16999 nk_start_buffer(ctx, &ctx->overlay);
17000
17001 mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x;
17002 mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y;
17003 mouse_bounds.w = cursor->size.x;
17004 mouse_bounds.h = cursor->size.y;
17005
17006 nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white);
17007 nk_finish_buffer(ctx, &ctx->overlay);
17008 }
17009 /* build one big draw command list out of all window buffers */
17010 iter = ctx->begin;
17011 buffer = (nk_byte*)ctx->memory.memory.ptr;
17012 while (iter != 0) {
17013 struct nk_window *next = iter->next;
17014 if (iter->buffer.last == iter->buffer.begin || (iter->flags & NK_WINDOW_HIDDEN))
17015 goto cont;
17016
17017 cmd = nk_ptr_add(struct nk_command, buffer, iter->buffer.last);
17018 while (next && ((next->buffer.last == next->buffer.begin) ||
17019 (next->flags & NK_WINDOW_HIDDEN)))
17020 next = next->next; /* skip empty command buffers */
17021
17022 if (next) cmd->next = next->buffer.begin;
17023 cont: iter = next;
17024 }
17025 /* append all popup draw commands into lists */
17026 iter = ctx->begin;
17027 while (iter != 0) {
17028 struct nk_window *next = iter->next;
17029 struct nk_popup_buffer *buf;
17030 if (!iter->popup.buf.active)
17031 goto skip;
17032
17033 buf = &iter->popup.buf;
17034 cmd->next = buf->begin;
17035 cmd = nk_ptr_add(struct nk_command, buffer, buf->last);
17036 buf->active = nk_false;
17037 skip: iter = next;
17038 }
17039 /* append overlay commands */
17040 if (cmd) {
17041 if (ctx->overlay.end != ctx->overlay.begin)
17042 cmd->next = ctx->overlay.begin;
17043 else cmd->next = ctx->memory.allocated;
17044 }
17045}
17046
17047NK_API const struct nk_command*
17048nk__begin(struct nk_context *ctx)
17049{
17050 struct nk_window *iter;
17051 nk_byte *buffer;
17052 NK_ASSERT(ctx);
17053 if (!ctx) return 0;
17054 if (!ctx->count) return 0;
17055
17056 buffer = (nk_byte*)ctx->memory.memory.ptr;
17057 if (!ctx->build) {
17058 nk_build(ctx);
17059 ctx->build = nk_true;
17060 }
17061
17062 iter = ctx->begin;
17063 while (iter && ((iter->buffer.begin == iter->buffer.end) || (iter->flags & NK_WINDOW_HIDDEN)))
17064 iter = iter->next;
17065 if (!iter) return 0;
17066 return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin);
17067}
17068
17069NK_API const struct nk_command*
17070nk__next(struct nk_context *ctx, const struct nk_command *cmd)
17071{
17072 nk_byte *buffer;
17073 const struct nk_command *next;
17074 NK_ASSERT(ctx);
17075 if (!ctx || !cmd || !ctx->count) return 0;
17076 if (cmd->next >= ctx->memory.allocated) return 0;
17077 buffer = (nk_byte*)ctx->memory.memory.ptr;
17078 next = nk_ptr_add_const(struct nk_command, buffer, cmd->next);
17079 return next;
17080}
17081
17082/* ----------------------------------------------------------------
17083 *
17084 * PANEL
17085 *
17086 * ---------------------------------------------------------------*/
17087static int
17088nk_panel_has_header(nk_flags flags, const char *title)
17089{
17090 int active = 0;
17091 active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE));
17092 active = active || (flags & NK_WINDOW_TITLE);
17093 active = active && !(flags & NK_WINDOW_HIDDEN) && title;
17094 return active;
17095}
17096
17097NK_INTERN struct nk_vec2
17098nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type)
17099{
17100 switch (type) {
17101 default:
17102 case NK_PANEL_WINDOW: return style->window.padding;
17103 case NK_PANEL_GROUP: return style->window.group_padding;
17104 case NK_PANEL_POPUP: return style->window.popup_padding;
17105 case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding;
17106 case NK_PANEL_COMBO: return style->window.combo_padding;
17107 case NK_PANEL_MENU: return style->window.menu_padding;
17108 case NK_PANEL_TOOLTIP: return style->window.menu_padding;
17109 }
17110}
17111
17112NK_INTERN float
17113nk_panel_get_border(const struct nk_style *style, nk_flags flags,
17114 enum nk_panel_type type)
17115{
17116 if (flags & NK_WINDOW_BORDER) {
17117 switch (type) {
17118 default:
17119 case NK_PANEL_WINDOW: return style->window.border;
17120 case NK_PANEL_GROUP: return style->window.group_border;
17121 case NK_PANEL_POPUP: return style->window.popup_border;
17122 case NK_PANEL_CONTEXTUAL: return style->window.contextual_border;
17123 case NK_PANEL_COMBO: return style->window.combo_border;
17124 case NK_PANEL_MENU: return style->window.menu_border;
17125 case NK_PANEL_TOOLTIP: return style->window.menu_border;
17126 }} else return 0;
17127}
17128
17129NK_INTERN struct nk_color
17130nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type)
17131{
17132 switch (type) {
17133 default:
17134 case NK_PANEL_WINDOW: return style->window.border_color;
17135 case NK_PANEL_GROUP: return style->window.group_border_color;
17136 case NK_PANEL_POPUP: return style->window.popup_border_color;
17137 case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color;
17138 case NK_PANEL_COMBO: return style->window.combo_border_color;
17139 case NK_PANEL_MENU: return style->window.menu_border_color;
17140 case NK_PANEL_TOOLTIP: return style->window.menu_border_color;
17141 }
17142}
17143
17144NK_INTERN int
17145nk_panel_is_sub(enum nk_panel_type type)
17146{
17147 return (type & NK_PANEL_SET_SUB)?1:0;
17148}
17149
17150NK_INTERN int
17151nk_panel_is_nonblock(enum nk_panel_type type)
17152{
17153 return (type & NK_PANEL_SET_NONBLOCK)?1:0;
17154}
17155
17156NK_INTERN int
17157nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type)
17158{
17159 struct nk_input *in;
17160 struct nk_window *win;
17161 struct nk_panel *layout;
17162 struct nk_command_buffer *out;
17163 const struct nk_style *style;
17164 const struct nk_user_font *font;
17165
17166 struct nk_vec2 scrollbar_size;
17167 struct nk_vec2 panel_padding;
17168
17169 NK_ASSERT(ctx);
17170 NK_ASSERT(ctx->current);
17171 NK_ASSERT(ctx->current->layout);
17172 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
17173 nk_zero(ctx->current->layout, sizeof(*ctx->current->layout));
17174 if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) {
17175 nk_zero(ctx->current->layout, sizeof(struct nk_panel));
17176 ctx->current->layout->type = panel_type;
17177 return 0;
17178 }
17179 /* pull state into local stack */
17180 style = &ctx->style;
17181 font = style->font;
17182 win = ctx->current;
17183 layout = win->layout;
17184 out = &win->buffer;
17185 in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input;
17186#ifdef NK_INCLUDE_COMMAND_USERDATA
17187 win->buffer.userdata = ctx->userdata;
17188#endif
17189 /* pull style configuration into local stack */
17190 scrollbar_size = style->window.scrollbar_size;
17191 panel_padding = nk_panel_get_padding(style, panel_type);
17192
17193 /* window movement */
17194 if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) {
17195 int left_mouse_down;
17196 int left_mouse_click_in_cursor;
17197
17198 /* calculate draggable window space */
17199 struct nk_rect header;
17200 header.x = win->bounds.x;
17201 header.y = win->bounds.y;
17202 header.w = win->bounds.w;
17203 if (nk_panel_has_header(win->flags, title)) {
17204 header.h = font->height + 2.0f * style->window.header.padding.y;
17205 header.h += 2.0f * style->window.header.label_padding.y;
17206 } else header.h = panel_padding.y;
17207
17208 /* window movement by dragging */
17209 left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
17210 left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
17211 NK_BUTTON_LEFT, header, nk_true);
17212 if (left_mouse_down && left_mouse_click_in_cursor) {
17213 win->bounds.x = win->bounds.x + in->mouse.delta.x;
17214 win->bounds.y = win->bounds.y + in->mouse.delta.y;
17215 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x;
17216 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y;
17217 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE];
17218 }
17219 }
17220
17221 /* setup panel */
17222 layout->type = panel_type;
17223 layout->flags = win->flags;
17224 layout->bounds = win->bounds;
17225 layout->bounds.x += panel_padding.x;
17226 layout->bounds.w -= 2*panel_padding.x;
17227 if (win->flags & NK_WINDOW_BORDER) {
17228 layout->border = nk_panel_get_border(style, win->flags, panel_type);
17229 layout->bounds = nk_shrink_rect(layout->bounds, layout->border);
17230 } else layout->border = 0;
17231 layout->at_y = layout->bounds.y;
17232 layout->at_x = layout->bounds.x;
17233 layout->max_x = 0;
17234 layout->header_height = 0;
17235 layout->footer_height = 0;
17236 layout->row.index = 0;
17237 layout->row.columns = 0;
17238 layout->row.ratio = 0;
17239 layout->row.item_width = 0;
17240 layout->row.tree_depth = 0;
17241 layout->row.height = panel_padding.y;
17242 layout->has_scrolling = nk_true;
17243 if (!(win->flags & NK_WINDOW_NO_SCROLLBAR))
17244 layout->bounds.w -= scrollbar_size.x;
17245 if (!nk_panel_is_nonblock(panel_type)) {
17246 layout->footer_height = 0;
17247 if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE)
17248 layout->footer_height = scrollbar_size.y;
17249 layout->bounds.h -= layout->footer_height;
17250 }
17251
17252 /* panel header */
17253 if (nk_panel_has_header(win->flags, title))
17254 {
17255 struct nk_text text;
17256 struct nk_rect header;
17257 const struct nk_style_item *background = 0;
17258
17259 /* calculate header bounds */
17260 header.x = win->bounds.x;
17261 header.y = win->bounds.y;
17262 header.w = win->bounds.w;
17263 header.h = font->height + 2.0f * style->window.header.padding.y;
17264 header.h += (2.0f * style->window.header.label_padding.y);
17265
17266 /* shrink panel by header */
17267 layout->header_height = header.h;
17268 layout->bounds.y += header.h;
17269 layout->bounds.h -= header.h;
17270 layout->at_y += header.h;
17271
17272 /* select correct header background and text color */
17273 if (ctx->active == win) {
17274 background = &style->window.header.active;
17275 text.text = style->window.header.label_active;
17276 } else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) {
17277 background = &style->window.header.hover;
17278 text.text = style->window.header.label_hover;
17279 } else {
17280 background = &style->window.header.normal;
17281 text.text = style->window.header.label_normal;
17282 }
17283
17284 /* draw header background */
17285 header.h += 1.0f;
17286 if (background->type == NK_STYLE_ITEM_IMAGE) {
17287 text.background = nk_rgba(0,0,0,0);
17288 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
17289 } else {
17290 text.background = background->data.color;
17291 nk_fill_rect(out, header, 0, background->data.color);
17292 }
17293
17294 /* window close button */
17295 {struct nk_rect button;
17296 button.y = header.y + style->window.header.padding.y;
17297 button.h = header.h - 2 * style->window.header.padding.y;
17298 button.w = button.h;
17299 if (win->flags & NK_WINDOW_CLOSABLE) {
17300 nk_flags ws = 0;
17301 if (style->window.header.align == NK_HEADER_RIGHT) {
17302 button.x = (header.w + header.x) - (button.w + style->window.header.padding.x);
17303 header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x;
17304 } else {
17305 button.x = header.x + style->window.header.padding.x;
17306 header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;
17307 }
17308
17309 if (nk_do_button_symbol(&ws, &win->buffer, button,
17310 style->window.header.close_symbol, NK_BUTTON_DEFAULT,
17311 &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))
17312 {
17313 layout->flags |= NK_WINDOW_HIDDEN;
17314 layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED;
17315 }
17316 }
17317
17318 /* window minimize button */
17319 if (win->flags & NK_WINDOW_MINIMIZABLE) {
17320 nk_flags ws = 0;
17321 if (style->window.header.align == NK_HEADER_RIGHT) {
17322 button.x = (header.w + header.x) - button.w;
17323 if (!(win->flags & NK_WINDOW_CLOSABLE)) {
17324 button.x -= style->window.header.padding.x;
17325 header.w -= style->window.header.padding.x;
17326 }
17327 header.w -= button.w + style->window.header.spacing.x;
17328 } else {
17329 button.x = header.x;
17330 header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;
17331 }
17332 if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)?
17333 style->window.header.maximize_symbol: style->window.header.minimize_symbol,
17334 NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))
17335 layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ?
17336 layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED:
17337 layout->flags | NK_WINDOW_MINIMIZED;
17338 }}
17339
17340 {/* window header title */
17341 int text_len = nk_strlen(title);
17342 struct nk_rect label = {0,0,0,0};
17343 float t = font->width(font->userdata, font->height, title, text_len);
17344 text.padding = nk_vec2(0,0);
17345
17346 label.x = header.x + style->window.header.padding.x;
17347 label.x += style->window.header.label_padding.x;
17348 label.y = header.y + style->window.header.label_padding.y;
17349 label.h = font->height + 2 * style->window.header.label_padding.y;
17350 label.w = t + 2 * style->window.header.spacing.x;
17351 label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x);
17352 nk_widget_text(out, label,(const char*)title, text_len, &text, NK_TEXT_LEFT, font);}
17353 }
17354
17355 /* draw window background */
17356 if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) {
17357 struct nk_rect body;
17358 body.x = win->bounds.x;
17359 body.w = win->bounds.w;
17360 body.y = (win->bounds.y + layout->header_height);
17361 body.h = (win->bounds.h - layout->header_height);
17362 if (style->window.fixed_background.type == NK_STYLE_ITEM_IMAGE)
17363 nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white);
17364 else nk_fill_rect(out, body, 0, style->window.fixed_background.data.color);
17365 }
17366
17367 /* set clipping rectangle */
17368 {struct nk_rect clip;
17369 layout->clip = layout->bounds;
17370 nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y,
17371 layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h);
17372 nk_push_scissor(out, clip);
17373 layout->clip = clip;}
17374 return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED);
17375}
17376
17377NK_INTERN void
17378nk_panel_end(struct nk_context *ctx)
17379{
17380 struct nk_input *in;
17381 struct nk_window *window;
17382 struct nk_panel *layout;
17383 const struct nk_style *style;
17384 struct nk_command_buffer *out;
17385
17386 struct nk_vec2 scrollbar_size;
17387 struct nk_vec2 panel_padding;
17388
17389 NK_ASSERT(ctx);
17390 NK_ASSERT(ctx->current);
17391 NK_ASSERT(ctx->current->layout);
17392 if (!ctx || !ctx->current || !ctx->current->layout)
17393 return;
17394
17395 window = ctx->current;
17396 layout = window->layout;
17397 style = &ctx->style;
17398 out = &window->buffer;
17399 in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input;
17400 if (!nk_panel_is_sub(layout->type))
17401 nk_push_scissor(out, nk_null_rect);
17402
17403 /* cache configuration data */
17404 scrollbar_size = style->window.scrollbar_size;
17405 panel_padding = nk_panel_get_padding(style, layout->type);
17406
17407 /* update the current cursor Y-position to point over the last added widget */
17408 layout->at_y += layout->row.height;
17409
17410 /* dynamic panels */
17411 if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED))
17412 {
17413 /* update panel height to fit dynamic growth */
17414 struct nk_rect empty_space;
17415 if (layout->at_y < (layout->bounds.y + layout->bounds.h))
17416 layout->bounds.h = layout->at_y - layout->bounds.y;
17417
17418 /* fill top empty space */
17419 empty_space.x = window->bounds.x;
17420 empty_space.y = layout->bounds.y;
17421 empty_space.h = panel_padding.y;
17422 empty_space.w = window->bounds.w;
17423 nk_fill_rect(out, empty_space, 0, style->window.background);
17424
17425 /* fill left empty space */
17426 empty_space.x = window->bounds.x;
17427 empty_space.y = layout->bounds.y;
17428 empty_space.w = panel_padding.x + layout->border;
17429 empty_space.h = layout->bounds.h;
17430 nk_fill_rect(out, empty_space, 0, style->window.background);
17431
17432 /* fill right empty space */
17433 empty_space.x = layout->bounds.x + layout->bounds.w - layout->border;
17434 empty_space.y = layout->bounds.y;
17435 empty_space.w = panel_padding.x + layout->border;
17436 empty_space.h = layout->bounds.h;
17437 if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR))
17438 empty_space.w += scrollbar_size.x;
17439 nk_fill_rect(out, empty_space, 0, style->window.background);
17440
17441 /* fill bottom empty space */
17442 if (*layout->offset_x != 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) {
17443 empty_space.x = window->bounds.x;
17444 empty_space.y = layout->bounds.y + layout->bounds.h;
17445 empty_space.w = window->bounds.w;
17446 empty_space.h = scrollbar_size.y;
17447 nk_fill_rect(out, empty_space, 0, style->window.background);
17448 }
17449 }
17450
17451 /* scrollbars */
17452 if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) &&
17453 !(layout->flags & NK_WINDOW_MINIMIZED) &&
17454 window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT)
17455 {
17456 struct nk_rect scroll;
17457 int scroll_has_scrolling;
17458 float scroll_target;
17459 float scroll_offset;
17460 float scroll_step;
17461 float scroll_inc;
17462
17463 /* mouse wheel scrolling */
17464 if (nk_panel_is_sub(layout->type))
17465 {
17466 /* sub-window mouse wheel scrolling */
17467 struct nk_window *root_window = window;
17468 struct nk_panel *root_panel = window->layout;
17469 while (root_panel->parent)
17470 root_panel = root_panel->parent;
17471 while (root_window->parent)
17472 root_window = root_window->parent;
17473
17474 /* only allow scrolling if parent window is active */
17475 scroll_has_scrolling = 0;
17476 if ((root_window == ctx->active) && layout->has_scrolling) {
17477 /* and panel is being hovered and inside clip rect*/
17478 if (nk_input_is_mouse_hovering_rect(in, layout->bounds) &&
17479 NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h,
17480 root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h))
17481 {
17482 /* deactivate all parent scrolling */
17483 root_panel = window->layout;
17484 while (root_panel->parent) {
17485 root_panel->has_scrolling = nk_false;
17486 root_panel = root_panel->parent;
17487 }
17488 root_panel->has_scrolling = nk_false;
17489 scroll_has_scrolling = nk_true;
17490 }
17491 }
17492 } else if (!nk_panel_is_sub(layout->type)) {
17493 /* window mouse wheel scrolling */
17494 scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling;
17495 if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling)
17496 window->scrolled = nk_true;
17497 else window->scrolled = nk_false;
17498 } else scroll_has_scrolling = nk_false;
17499
17500 {
17501 /* vertical scrollbar */
17502 nk_flags state = 0;
17503 scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x;
17504 scroll.y = layout->bounds.y;
17505 scroll.w = scrollbar_size.x;
17506 scroll.h = layout->bounds.h;
17507
17508 scroll_offset = (float)*layout->offset_y;
17509 scroll_step = scroll.h * 0.10f;
17510 scroll_inc = scroll.h * 0.01f;
17511 scroll_target = (float)(int)(layout->at_y - scroll.y);
17512 scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling,
17513 scroll_offset, scroll_target, scroll_step, scroll_inc,
17514 &ctx->style.scrollv, in, style->font);
17515 *layout->offset_y = (nk_uint)scroll_offset;
17516 if (in && scroll_has_scrolling)
17517 in->mouse.scroll_delta.y = 0;
17518 }
17519 {
17520 /* horizontal scrollbar */
17521 nk_flags state = 0;
17522 scroll.x = layout->bounds.x;
17523 scroll.y = layout->bounds.y + layout->bounds.h;
17524 scroll.w = layout->bounds.w;
17525 scroll.h = scrollbar_size.y;
17526
17527 scroll_offset = (float)*layout->offset_x;
17528 scroll_target = (float)(int)(layout->max_x - scroll.x);
17529 scroll_step = layout->max_x * 0.05f;
17530 scroll_inc = layout->max_x * 0.005f;
17531 scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling,
17532 scroll_offset, scroll_target, scroll_step, scroll_inc,
17533 &ctx->style.scrollh, in, style->font);
17534 *layout->offset_x = (nk_uint)scroll_offset;
17535 }
17536 }
17537
17538 /* hide scroll if no user input */
17539 if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) {
17540 int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta.y != 0;
17541 int is_window_hovered = nk_window_is_hovered(ctx);
17542 int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);
17543 if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active))
17544 window->scrollbar_hiding_timer += ctx->delta_time_seconds;
17545 else window->scrollbar_hiding_timer = 0;
17546 } else window->scrollbar_hiding_timer = 0;
17547
17548 /* window border */
17549 if (layout->flags & NK_WINDOW_BORDER)
17550 {
17551 struct nk_color border_color = nk_panel_get_border_color(style, layout->type);
17552 const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED) ?
17553 style->window.border + window->bounds.y + layout->header_height:
17554 (layout->flags & NK_WINDOW_DYNAMIC)?
17555 layout->bounds.y + layout->bounds.h + layout->footer_height:
17556 window->bounds.y + window->bounds.h;
17557
17558 /* draw border top */
17559 nk_stroke_line(out,window->bounds.x,window->bounds.y,
17560 window->bounds.x + window->bounds.w, window->bounds.y,
17561 layout->border, border_color);
17562
17563 /* draw bottom border */
17564 nk_stroke_line(out, window->bounds.x, padding_y,
17565 window->bounds.x + window->bounds.w, padding_y, layout->border, border_color);
17566
17567 /* draw left border */
17568 nk_stroke_line(out, window->bounds.x + layout->border*0.5f,
17569 window->bounds.y, window->bounds.x + layout->border*0.5f,
17570 padding_y, layout->border, border_color);
17571
17572 /* draw right border */
17573 nk_stroke_line(out, window->bounds.x + window->bounds.w - layout->border*0.5f,
17574 window->bounds.y, window->bounds.x + window->bounds.w - layout->border*0.5f,
17575 padding_y, layout->border, border_color);
17576 }
17577
17578 /* scaler */
17579 if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED))
17580 {
17581 /* calculate scaler bounds */
17582 struct nk_rect scaler;
17583 scaler.w = scrollbar_size.x;
17584 scaler.h = scrollbar_size.y;
17585 scaler.y = layout->bounds.y + layout->bounds.h;
17586 if (layout->flags & NK_WINDOW_SCALE_LEFT)
17587 scaler.x = layout->bounds.x - panel_padding.x * 0.5f;
17588 else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x;
17589 if (layout->flags & NK_WINDOW_NO_SCROLLBAR)
17590 scaler.x -= scaler.w;
17591
17592 /* draw scaler */
17593 {const struct nk_style_item *item = &style->window.scaler;
17594 if (item->type == NK_STYLE_ITEM_IMAGE)
17595 nk_draw_image(out, scaler, &item->data.image, nk_white);
17596 else {
17597 if (layout->flags & NK_WINDOW_SCALE_LEFT) {
17598 nk_fill_triangle(out, scaler.x, scaler.y, scaler.x,
17599 scaler.y + scaler.h, scaler.x + scaler.w,
17600 scaler.y + scaler.h, item->data.color);
17601 } else {
17602 nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w,
17603 scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color);
17604 }
17605 }}
17606
17607 /* do window scaling */
17608 if (!(window->flags & NK_WINDOW_ROM)) {
17609 struct nk_vec2 window_size = style->window.min_size;
17610 int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
17611 int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in,
17612 NK_BUTTON_LEFT, scaler, nk_true);
17613
17614 if (nk_input_is_mouse_down(in, NK_BUTTON_LEFT) && left_mouse_down && left_mouse_click_in_scaler) {
17615 float delta_x = in->mouse.delta.x;
17616 if (layout->flags & NK_WINDOW_SCALE_LEFT) {
17617 delta_x = -delta_x;
17618 window->bounds.x += in->mouse.delta.x;
17619 }
17620 window->bounds.w = NK_MAX(window_size.x, window->bounds.w + delta_x);
17621
17622 /* dragging in y-direction is only possible if static window */
17623 if (!(layout->flags & NK_WINDOW_DYNAMIC))
17624 window->bounds.h = NK_MAX(window_size.y, window->bounds.h + in->mouse.delta.y);
17625 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT];
17626 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + in->mouse.delta.x + scaler.w/2.0f;
17627 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + in->mouse.delta.y + scaler.h/2.0f;
17628 }
17629 }
17630 }
17631 if (!nk_panel_is_sub(layout->type)) {
17632 /* window is hidden so clear command buffer */
17633 if (layout->flags & NK_WINDOW_HIDDEN)
17634 nk_command_buffer_reset(&window->buffer);
17635 /* window is visible and not tab */
17636 else nk_finish(ctx, window);
17637 }
17638
17639 /* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */
17640 if (layout->flags & NK_WINDOW_REMOVE_ROM) {
17641 layout->flags &= ~(nk_flags)NK_WINDOW_ROM;
17642 layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;
17643 }
17644 window->flags = layout->flags;
17645
17646 /* property garbage collector */
17647 if (window->property.active && window->property.old != window->property.seq &&
17648 window->property.active == window->property.prev) {
17649 nk_zero(&window->property, sizeof(window->property));
17650 } else {
17651 window->property.old = window->property.seq;
17652 window->property.prev = window->property.active;
17653 window->property.seq = 0;
17654 }
17655 /* edit garbage collector */
17656 if (window->edit.active && window->edit.old != window->edit.seq &&
17657 window->edit.active == window->edit.prev) {
17658 nk_zero(&window->edit, sizeof(window->edit));
17659 } else {
17660 window->edit.old = window->edit.seq;
17661 window->edit.prev = window->edit.active;
17662 window->edit.seq = 0;
17663 }
17664 /* contextual garbage collector */
17665 if (window->popup.active_con && window->popup.con_old != window->popup.con_count) {
17666 window->popup.con_count = 0;
17667 window->popup.con_old = 0;
17668 window->popup.active_con = 0;
17669 } else {
17670 window->popup.con_old = window->popup.con_count;
17671 window->popup.con_count = 0;
17672 }
17673 window->popup.combo_count = 0;
17674
17675 /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */
17676 NK_ASSERT(!layout->row.tree_depth);
17677}
17678
17679/* ----------------------------------------------------------------
17680 *
17681 * PAGE ELEMENT
17682 *
17683 * ---------------------------------------------------------------*/
17684NK_INTERN struct nk_page_element*
17685nk_create_page_element(struct nk_context *ctx)
17686{
17687 struct nk_page_element *elem;
17688 if (ctx->freelist) {
17689 /* unlink page element from free list */
17690 elem = ctx->freelist;
17691 ctx->freelist = elem->next;
17692 } else if (ctx->use_pool) {
17693 /* allocate page element from memory pool */
17694 elem = nk_pool_alloc(&ctx->pool);
17695 NK_ASSERT(elem);
17696 if (!elem) return 0;
17697 } else {
17698 /* allocate new page element from back of fixed size memory buffer */
17699 NK_STORAGE const nk_size size = sizeof(struct nk_page_element);
17700 NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element);
17701 elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align);
17702 NK_ASSERT(elem);
17703 if (!elem) return 0;
17704 }
17705 nk_zero_struct(*elem);
17706 elem->next = 0;
17707 elem->prev = 0;
17708 return elem;
17709}
17710
17711NK_INTERN void
17712nk_link_page_element_into_freelist(struct nk_context *ctx,
17713 struct nk_page_element *elem)
17714{
17715 /* link table into freelist */
17716 if (!ctx->freelist) {
17717 ctx->freelist = elem;
17718 } else {
17719 elem->next = ctx->freelist;
17720 ctx->freelist = elem;
17721 }
17722}
17723
17724NK_INTERN void
17725nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem)
17726{
17727 /* we have a pool so just add to free list */
17728 if (ctx->use_pool) {
17729 nk_link_page_element_into_freelist(ctx, elem);
17730 return;
17731 }
17732 /* if possible remove last element from back of fixed memory buffer */
17733 {void *elem_end = (void*)(elem + 1);
17734 void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size;
17735 if (elem_end == buffer_end)
17736 ctx->memory.size -= sizeof(struct nk_page_element);
17737 else nk_link_page_element_into_freelist(ctx, elem);}
17738}
17739
17740/* ----------------------------------------------------------------
17741 *
17742 * PANEL
17743 *
17744 * ---------------------------------------------------------------*/
17745NK_INTERN void*
17746nk_create_panel(struct nk_context *ctx)
17747{
17748 struct nk_page_element *elem;
17749 elem = nk_create_page_element(ctx);
17750 if (!elem) return 0;
17751 nk_zero_struct(*elem);
17752 return &elem->data.pan;
17753}
17754
17755NK_INTERN void
17756nk_free_panel(struct nk_context *ctx, struct nk_panel *pan)
17757{
17758 union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan);
17759 struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
17760 nk_free_page_element(ctx, pe);
17761}
17762
17763/* ----------------------------------------------------------------
17764 *
17765 * TABLES
17766 *
17767 * ---------------------------------------------------------------*/
17768NK_INTERN struct nk_table*
17769nk_create_table(struct nk_context *ctx)
17770{
17771 struct nk_page_element *elem;
17772 elem = nk_create_page_element(ctx);
17773 if (!elem) return 0;
17774 nk_zero_struct(*elem);
17775 return &elem->data.tbl;
17776}
17777
17778NK_INTERN void
17779nk_free_table(struct nk_context *ctx, struct nk_table *tbl)
17780{
17781 union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl);
17782 struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
17783 nk_free_page_element(ctx, pe);
17784}
17785
17786NK_INTERN void
17787nk_push_table(struct nk_window *win, struct nk_table *tbl)
17788{
17789 if (!win->tables) {
17790 win->tables = tbl;
17791 tbl->next = 0;
17792 tbl->prev = 0;
17793 win->table_count = 1;
17794 win->table_size = 0;
17795 return;
17796 }
17797 win->tables->prev = tbl;
17798 tbl->next = win->tables;
17799 tbl->prev = 0;
17800 win->tables = tbl;
17801 win->table_count++;
17802 win->table_size = 0;
17803}
17804
17805NK_INTERN void
17806nk_remove_table(struct nk_window *win, struct nk_table *tbl)
17807{
17808 if (win->tables == tbl)
17809 win->tables = tbl->next;
17810 if (tbl->next)
17811 tbl->next->prev = tbl->prev;
17812 if (tbl->prev)
17813 tbl->prev->next = tbl->next;
17814 tbl->next = 0;
17815 tbl->prev = 0;
17816}
17817
17818NK_INTERN nk_uint*
17819nk_add_value(struct nk_context *ctx, struct nk_window *win,
17820 nk_hash name, nk_uint value)
17821{
17822 NK_ASSERT(ctx);
17823 NK_ASSERT(win);
17824 if (!win || !ctx) return 0;
17825 if (!win->tables || win->table_size >= NK_VALUE_PAGE_CAPACITY) {
17826 struct nk_table *tbl = nk_create_table(ctx);
17827 NK_ASSERT(tbl);
17828 if (!tbl) return 0;
17829 nk_push_table(win, tbl);
17830 }
17831 win->tables->seq = win->seq;
17832 win->tables->keys[win->table_size] = name;
17833 win->tables->values[win->table_size] = value;
17834 return &win->tables->values[win->table_size++];
17835}
17836
17837NK_INTERN nk_uint*
17838nk_find_value(struct nk_window *win, nk_hash name)
17839{
17840 nk_ushort size = win->table_size;
17841 struct nk_table *iter = win->tables;
17842 while (iter) {
17843 nk_ushort i = 0;
17844 for (i = 0; i < size; ++i) {
17845 if (iter->keys[i] == name) {
17846 iter->seq = win->seq;
17847 return &iter->values[i];
17848 }
17849 }
17850 size = NK_VALUE_PAGE_CAPACITY;
17851 iter = iter->next;
17852 }
17853 return 0;
17854}
17855
17856/* ----------------------------------------------------------------
17857 *
17858 * WINDOW
17859 *
17860 * ---------------------------------------------------------------*/
17861NK_INTERN void*
17862nk_create_window(struct nk_context *ctx)
17863{
17864 struct nk_page_element *elem;
17865 elem = nk_create_page_element(ctx);
17866 if (!elem) return 0;
17867 elem->data.win.seq = ctx->seq;
17868 return &elem->data.win;
17869}
17870
17871NK_INTERN void
17872nk_free_window(struct nk_context *ctx, struct nk_window *win)
17873{
17874 /* unlink windows from list */
17875 struct nk_table *it = win->tables;
17876 if (win->popup.win) {
17877 nk_free_window(ctx, win->popup.win);
17878 win->popup.win = 0;
17879 }
17880 win->next = 0;
17881 win->prev = 0;
17882
17883 while (it) {
17884 /*free window state tables */
17885 struct nk_table *n = it->next;
17886 nk_remove_table(win, it);
17887 nk_free_table(ctx, it);
17888 if (it == win->tables)
17889 win->tables = n;
17890 it = n;
17891 }
17892
17893 /* link windows into freelist */
17894 {union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win);
17895 struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
17896 nk_free_page_element(ctx, pe);}
17897}
17898
17899NK_INTERN struct nk_window*
17900nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name)
17901{
17902 struct nk_window *iter;
17903 iter = ctx->begin;
17904 while (iter) {
17905 NK_ASSERT(iter != iter->next);
17906 if (iter->name == hash) {
17907 int max_len = nk_strlen(iter->name_string);
17908 if (!nk_stricmpn(iter->name_string, name, max_len))
17909 return iter;
17910 }
17911 iter = iter->next;
17912 }
17913 return 0;
17914}
17915
17916enum nk_window_insert_location {
17917 NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */
17918 NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */
17919};
17920NK_INTERN void
17921nk_insert_window(struct nk_context *ctx, struct nk_window *win,
17922 enum nk_window_insert_location loc)
17923{
17924 const struct nk_window *iter;
17925 NK_ASSERT(ctx);
17926 NK_ASSERT(win);
17927 if (!win || !ctx) return;
17928
17929 iter = ctx->begin;
17930 while (iter) {
17931 NK_ASSERT(iter != iter->next);
17932 NK_ASSERT(iter != win);
17933 if (iter == win) return;
17934 iter = iter->next;
17935 }
17936
17937 if (!ctx->begin) {
17938 win->next = 0;
17939 win->prev = 0;
17940 ctx->begin = win;
17941 ctx->end = win;
17942 ctx->count = 1;
17943 return;
17944 }
17945 if (loc == NK_INSERT_BACK) {
17946 struct nk_window *end;
17947 end = ctx->end;
17948 end->flags |= NK_WINDOW_ROM;
17949 end->next = win;
17950 win->prev = ctx->end;
17951 win->next = 0;
17952 ctx->end = win;
17953 ctx->active = ctx->end;
17954 ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;
17955 } else {
17956 ctx->end->flags |= NK_WINDOW_ROM;
17957 ctx->begin->prev = win;
17958 win->next = ctx->begin;
17959 win->prev = 0;
17960 ctx->begin = win;
17961 ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM;
17962 }
17963 ctx->count++;
17964}
17965
17966NK_INTERN void
17967nk_remove_window(struct nk_context *ctx, struct nk_window *win)
17968{
17969 if (win == ctx->begin || win == ctx->end) {
17970 if (win == ctx->begin) {
17971 ctx->begin = win->next;
17972 if (win->next)
17973 win->next->prev = 0;
17974 }
17975 if (win == ctx->end) {
17976 ctx->end = win->prev;
17977 if (win->prev)
17978 win->prev->next = 0;
17979 }
17980 } else {
17981 if (win->next)
17982 win->next->prev = win->prev;
17983 if (win->prev)
17984 win->prev->next = win->next;
17985 }
17986 if (win == ctx->active || !ctx->active) {
17987 ctx->active = ctx->end;
17988 if (ctx->end)
17989 ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;
17990 }
17991 win->next = 0;
17992 win->prev = 0;
17993 ctx->count--;
17994}
17995
17996NK_API int
17997nk_begin(struct nk_context *ctx, const char *title,
17998 struct nk_rect bounds, nk_flags flags)
17999{
18000 return nk_begin_titled(ctx, title, title, bounds, flags);
18001}
18002
18003NK_API int
18004nk_begin_titled(struct nk_context *ctx, const char *name, const char *title,
18005 struct nk_rect bounds, nk_flags flags)
18006{
18007 struct nk_window *win;
18008 struct nk_style *style;
18009 nk_hash title_hash;
18010 int title_len;
18011 int ret = 0;
18012
18013 NK_ASSERT(ctx);
18014 NK_ASSERT(name);
18015 NK_ASSERT(title);
18016 NK_ASSERT(ctx->style.font && ctx->style.font->width && "if this triggers you forgot to add a font");
18017 NK_ASSERT(!ctx->current && "if this triggers you missed a `nk_end` call");
18018 if (!ctx || ctx->current || !title || !name)
18019 return 0;
18020
18021 /* find or create window */
18022 style = &ctx->style;
18023 title_len = (int)nk_strlen(name);
18024 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18025 win = nk_find_window(ctx, title_hash, name);
18026 if (!win) {
18027 /* create new window */
18028 nk_size name_length = (nk_size)nk_strlen(name);
18029 win = (struct nk_window*)nk_create_window(ctx);
18030 NK_ASSERT(win);
18031 if (!win) return 0;
18032
18033 if (flags & NK_WINDOW_BACKGROUND)
18034 nk_insert_window(ctx, win, NK_INSERT_FRONT);
18035 else nk_insert_window(ctx, win, NK_INSERT_BACK);
18036 nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON);
18037
18038 win->flags = flags;
18039 win->bounds = bounds;
18040 win->name = title_hash;
18041 name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1);
18042 NK_MEMCPY(win->name_string, name, name_length);
18043 win->name_string[name_length] = 0;
18044 win->popup.win = 0;
18045 if (!ctx->active)
18046 ctx->active = win;
18047 } else {
18048 /* update window */
18049 win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1);
18050 win->flags |= flags;
18051 if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE)))
18052 win->bounds = bounds;
18053 /* If this assert triggers you either:
18054 *
18055 * I.) Have more than one window with the same name or
18056 * II.) You forgot to actually draw the window.
18057 * More specific you did not call `nk_clear` (nk_clear will be
18058 * automatically called for you if you are using one of the
18059 * provided demo backends). */
18060 NK_ASSERT(win->seq != ctx->seq);
18061 win->seq = ctx->seq;
18062 if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN))
18063 ctx->active = win;
18064 }
18065 if (win->flags & NK_WINDOW_HIDDEN) {
18066 ctx->current = win;
18067 win->layout = 0;
18068 return 0;
18069 }
18070
18071 /* window overlapping */
18072 if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT))
18073 {
18074 int inpanel, ishovered;
18075 const struct nk_window *iter = win;
18076 float h = ctx->style.font->height + 2.0f * style->window.header.padding.y +
18077 (2.0f * style->window.header.label_padding.y);
18078 struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))?
18079 win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h);
18080
18081 /* activate window if hovered and no other window is overlapping this window */
18082 nk_start(ctx, win);
18083 inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true);
18084 inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked;
18085 ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds);
18086 if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) {
18087 iter = win->next;
18088 while (iter) {
18089 struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?
18090 iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);
18091 if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
18092 iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&
18093 (!(iter->flags & NK_WINDOW_HIDDEN) || !(iter->flags & NK_WINDOW_BACKGROUND)))
18094 break;
18095
18096 if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&
18097 NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
18098 iter->popup.win->bounds.x, iter->popup.win->bounds.y,
18099 iter->popup.win->bounds.w, iter->popup.win->bounds.h))
18100 break;
18101 iter = iter->next;
18102 }
18103 }
18104
18105 /* activate window if clicked */
18106 if (iter && inpanel && (win != ctx->end) && !(iter->flags & NK_WINDOW_BACKGROUND)) {
18107 iter = win->next;
18108 while (iter) {
18109 /* try to find a panel with higher priority in the same position */
18110 struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?
18111 iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);
18112 if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y,
18113 iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&
18114 !(iter->flags & NK_WINDOW_HIDDEN))
18115 break;
18116 if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&
18117 NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
18118 iter->popup.win->bounds.x, iter->popup.win->bounds.y,
18119 iter->popup.win->bounds.w, iter->popup.win->bounds.h))
18120 break;
18121 iter = iter->next;
18122 }
18123 }
18124
18125 if (!iter && ctx->end != win) {
18126 if (!(win->flags & NK_WINDOW_BACKGROUND)) {
18127 /* current window is active in that position so transfer to top
18128 * at the highest priority in stack */
18129 nk_remove_window(ctx, win);
18130 nk_insert_window(ctx, win, NK_INSERT_BACK);
18131 }
18132 win->flags &= ~(nk_flags)NK_WINDOW_ROM;
18133 ctx->active = win;
18134 }
18135 if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND))
18136 win->flags |= NK_WINDOW_ROM;
18137 }
18138
18139 win->layout = (struct nk_panel*)nk_create_panel(ctx);
18140 ctx->current = win;
18141 ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW);
18142 win->layout->offset_x = &win->scrollbar.x;
18143 win->layout->offset_y = &win->scrollbar.y;
18144 return ret;
18145}
18146
18147NK_API void
18148nk_end(struct nk_context *ctx)
18149{
18150 struct nk_panel *layout;
18151 NK_ASSERT(ctx);
18152 NK_ASSERT(ctx->current && "if this triggers you forgot to call `nk_begin`");
18153 if (!ctx || !ctx->current)
18154 return;
18155
18156 layout = ctx->current->layout;
18157 if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) {
18158 ctx->current = 0;
18159 return;
18160 }
18161 nk_panel_end(ctx);
18162 nk_free_panel(ctx, ctx->current->layout);
18163 ctx->current = 0;
18164}
18165
18166NK_API struct nk_rect
18167nk_window_get_bounds(const struct nk_context *ctx)
18168{
18169 NK_ASSERT(ctx);
18170 NK_ASSERT(ctx->current);
18171 if (!ctx || !ctx->current) return nk_rect(0,0,0,0);
18172 return ctx->current->bounds;
18173}
18174
18175NK_API struct nk_vec2
18176nk_window_get_position(const struct nk_context *ctx)
18177{
18178 NK_ASSERT(ctx);
18179 NK_ASSERT(ctx->current);
18180 if (!ctx || !ctx->current) return nk_vec2(0,0);
18181 return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y);
18182}
18183
18184NK_API struct nk_vec2
18185nk_window_get_size(const struct nk_context *ctx)
18186{
18187 NK_ASSERT(ctx);
18188 NK_ASSERT(ctx->current);
18189 if (!ctx || !ctx->current) return nk_vec2(0,0);
18190 return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h);
18191}
18192
18193NK_API float
18194nk_window_get_width(const struct nk_context *ctx)
18195{
18196 NK_ASSERT(ctx);
18197 NK_ASSERT(ctx->current);
18198 if (!ctx || !ctx->current) return 0;
18199 return ctx->current->bounds.w;
18200}
18201
18202NK_API float
18203nk_window_get_height(const struct nk_context *ctx)
18204{
18205 NK_ASSERT(ctx);
18206 NK_ASSERT(ctx->current);
18207 if (!ctx || !ctx->current) return 0;
18208 return ctx->current->bounds.h;
18209}
18210
18211NK_API struct nk_rect
18212nk_window_get_content_region(struct nk_context *ctx)
18213{
18214 NK_ASSERT(ctx);
18215 NK_ASSERT(ctx->current);
18216 if (!ctx || !ctx->current) return nk_rect(0,0,0,0);
18217 return ctx->current->layout->clip;
18218}
18219
18220NK_API struct nk_vec2
18221nk_window_get_content_region_min(struct nk_context *ctx)
18222{
18223 NK_ASSERT(ctx);
18224 NK_ASSERT(ctx->current);
18225 NK_ASSERT(ctx->current->layout);
18226 if (!ctx || !ctx->current) return nk_vec2(0,0);
18227 return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y);
18228}
18229
18230NK_API struct nk_vec2
18231nk_window_get_content_region_max(struct nk_context *ctx)
18232{
18233 NK_ASSERT(ctx);
18234 NK_ASSERT(ctx->current);
18235 NK_ASSERT(ctx->current->layout);
18236 if (!ctx || !ctx->current) return nk_vec2(0,0);
18237 return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w,
18238 ctx->current->layout->clip.y + ctx->current->layout->clip.h);
18239}
18240
18241NK_API struct nk_vec2
18242nk_window_get_content_region_size(struct nk_context *ctx)
18243{
18244 NK_ASSERT(ctx);
18245 NK_ASSERT(ctx->current);
18246 NK_ASSERT(ctx->current->layout);
18247 if (!ctx || !ctx->current) return nk_vec2(0,0);
18248 return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h);
18249}
18250
18251NK_API struct nk_command_buffer*
18252nk_window_get_canvas(struct nk_context *ctx)
18253{
18254 NK_ASSERT(ctx);
18255 NK_ASSERT(ctx->current);
18256 NK_ASSERT(ctx->current->layout);
18257 if (!ctx || !ctx->current) return 0;
18258 return &ctx->current->buffer;
18259}
18260
18261NK_API struct nk_panel*
18262nk_window_get_panel(struct nk_context *ctx)
18263{
18264 NK_ASSERT(ctx);
18265 NK_ASSERT(ctx->current);
18266 if (!ctx || !ctx->current) return 0;
18267 return ctx->current->layout;
18268}
18269
18270NK_API int
18271nk_window_has_focus(const struct nk_context *ctx)
18272{
18273 NK_ASSERT(ctx);
18274 NK_ASSERT(ctx->current);
18275 NK_ASSERT(ctx->current->layout);
18276 if (!ctx || !ctx->current) return 0;
18277 return ctx->current == ctx->active;
18278}
18279
18280NK_API int
18281nk_window_is_hovered(struct nk_context *ctx)
18282{
18283 NK_ASSERT(ctx);
18284 NK_ASSERT(ctx->current);
18285 if (!ctx || !ctx->current) return 0;
18286 return nk_input_is_mouse_hovering_rect(&ctx->input, ctx->current->bounds);
18287}
18288
18289NK_API int
18290nk_window_is_any_hovered(struct nk_context *ctx)
18291{
18292 struct nk_window *iter;
18293 NK_ASSERT(ctx);
18294 if (!ctx) return 0;
18295 iter = ctx->begin;
18296 while (iter) {
18297 /* check if window is being hovered */
18298 if (iter->flags & NK_WINDOW_MINIMIZED) {
18299 struct nk_rect header = iter->bounds;
18300 header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y;
18301 if (nk_input_is_mouse_hovering_rect(&ctx->input, header))
18302 return 1;
18303 } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) {
18304 return 1;
18305 }
18306 /* check if window popup is being hovered */
18307 if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds))
18308 return 1;
18309 iter = iter->next;
18310 }
18311 return 0;
18312}
18313
18314NK_API int
18315nk_item_is_any_active(struct nk_context *ctx)
18316{
18317 int any_hovered = nk_window_is_any_hovered(ctx);
18318 int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);
18319 return any_hovered || any_active;
18320}
18321
18322NK_API int
18323nk_window_is_collapsed(struct nk_context *ctx, const char *name)
18324{
18325 int title_len;
18326 nk_hash title_hash;
18327 struct nk_window *win;
18328 NK_ASSERT(ctx);
18329 if (!ctx) return 0;
18330
18331 title_len = (int)nk_strlen(name);
18332 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18333 win = nk_find_window(ctx, title_hash, name);
18334 if (!win) return 0;
18335 return win->flags & NK_WINDOW_MINIMIZED;
18336}
18337
18338NK_API int
18339nk_window_is_closed(struct nk_context *ctx, const char *name)
18340{
18341 int title_len;
18342 nk_hash title_hash;
18343 struct nk_window *win;
18344 NK_ASSERT(ctx);
18345 if (!ctx) return 1;
18346
18347 title_len = (int)nk_strlen(name);
18348 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18349 win = nk_find_window(ctx, title_hash, name);
18350 if (!win) return 1;
18351 return (win->flags & NK_WINDOW_CLOSED);
18352}
18353
18354NK_API int
18355nk_window_is_hidden(struct nk_context *ctx, const char *name)
18356{
18357 int title_len;
18358 nk_hash title_hash;
18359 struct nk_window *win;
18360 NK_ASSERT(ctx);
18361 if (!ctx) return 1;
18362
18363 title_len = (int)nk_strlen(name);
18364 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18365 win = nk_find_window(ctx, title_hash, name);
18366 if (!win) return 1;
18367 return (win->flags & NK_WINDOW_HIDDEN);
18368}
18369
18370NK_API int
18371nk_window_is_active(struct nk_context *ctx, const char *name)
18372{
18373 int title_len;
18374 nk_hash title_hash;
18375 struct nk_window *win;
18376 NK_ASSERT(ctx);
18377 if (!ctx) return 0;
18378
18379 title_len = (int)nk_strlen(name);
18380 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18381 win = nk_find_window(ctx, title_hash, name);
18382 if (!win) return 0;
18383 return win == ctx->active;
18384}
18385
18386NK_API struct nk_window*
18387nk_window_find(struct nk_context *ctx, const char *name)
18388{
18389 int title_len;
18390 nk_hash title_hash;
18391 title_len = (int)nk_strlen(name);
18392 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18393 return nk_find_window(ctx, title_hash, name);
18394}
18395
18396NK_API void
18397nk_window_close(struct nk_context *ctx, const char *name)
18398{
18399 struct nk_window *win;
18400 NK_ASSERT(ctx);
18401 if (!ctx) return;
18402 win = nk_window_find(ctx, name);
18403 if (!win) return;
18404 NK_ASSERT(ctx->current != win && "You cannot close a currently active window");
18405 if (ctx->current == win) return;
18406 win->flags |= NK_WINDOW_HIDDEN;
18407 win->flags |= NK_WINDOW_CLOSED;
18408}
18409
18410NK_API void
18411nk_window_set_bounds(struct nk_context *ctx, struct nk_rect bounds)
18412{
18413 NK_ASSERT(ctx); NK_ASSERT(ctx->current);
18414 if (!ctx || !ctx->current) return;
18415 ctx->current->bounds = bounds;
18416}
18417
18418NK_API void
18419nk_window_set_position(struct nk_context *ctx, struct nk_vec2 pos)
18420{
18421 NK_ASSERT(ctx); NK_ASSERT(ctx->current);
18422 if (!ctx || !ctx->current) return;
18423 ctx->current->bounds.x = pos.x;
18424 ctx->current->bounds.y = pos.y;
18425}
18426
18427NK_API void
18428nk_window_set_size(struct nk_context *ctx, struct nk_vec2 size)
18429{
18430 NK_ASSERT(ctx); NK_ASSERT(ctx->current);
18431 if (!ctx || !ctx->current) return;
18432 ctx->current->bounds.w = size.x;
18433 ctx->current->bounds.h = size.y;
18434}
18435
18436NK_API void
18437nk_window_collapse(struct nk_context *ctx, const char *name,
18438 enum nk_collapse_states c)
18439{
18440 int title_len;
18441 nk_hash title_hash;
18442 struct nk_window *win;
18443 NK_ASSERT(ctx);
18444 if (!ctx) return;
18445
18446 title_len = (int)nk_strlen(name);
18447 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18448 win = nk_find_window(ctx, title_hash, name);
18449 if (!win) return;
18450 if (c == NK_MINIMIZED)
18451 win->flags |= NK_WINDOW_MINIMIZED;
18452 else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED;
18453}
18454
18455NK_API void
18456nk_window_collapse_if(struct nk_context *ctx, const char *name,
18457 enum nk_collapse_states c, int cond)
18458{
18459 NK_ASSERT(ctx);
18460 if (!ctx || !cond) return;
18461 nk_window_collapse(ctx, name, c);
18462}
18463
18464NK_API void
18465nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s)
18466{
18467 int title_len;
18468 nk_hash title_hash;
18469 struct nk_window *win;
18470 NK_ASSERT(ctx);
18471 if (!ctx) return;
18472
18473 title_len = (int)nk_strlen(name);
18474 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18475 win = nk_find_window(ctx, title_hash, name);
18476 if (!win) return;
18477 if (s == NK_HIDDEN) {
18478 win->flags |= NK_WINDOW_HIDDEN;
18479 } else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN;
18480}
18481
18482NK_API void
18483nk_window_show_if(struct nk_context *ctx, const char *name,
18484 enum nk_show_states s, int cond)
18485{
18486 NK_ASSERT(ctx);
18487 if (!ctx || !cond) return;
18488 nk_window_show(ctx, name, s);
18489}
18490
18491NK_API void
18492nk_window_set_focus(struct nk_context *ctx, const char *name)
18493{
18494 int title_len;
18495 nk_hash title_hash;
18496 struct nk_window *win;
18497 NK_ASSERT(ctx);
18498 if (!ctx) return;
18499
18500 title_len = (int)nk_strlen(name);
18501 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18502 win = nk_find_window(ctx, title_hash, name);
18503 if (win && ctx->end != win) {
18504 nk_remove_window(ctx, win);
18505 nk_insert_window(ctx, win, NK_INSERT_BACK);
18506 }
18507 ctx->active = win;
18508}
18509
18510/*----------------------------------------------------------------
18511 *
18512 * MENUBAR
18513 *
18514 * --------------------------------------------------------------*/
18515NK_API void
18516nk_menubar_begin(struct nk_context *ctx)
18517{
18518 struct nk_panel *layout;
18519 NK_ASSERT(ctx);
18520 NK_ASSERT(ctx->current);
18521 NK_ASSERT(ctx->current->layout);
18522 if (!ctx || !ctx->current || !ctx->current->layout)
18523 return;
18524
18525 layout = ctx->current->layout;
18526 NK_ASSERT(layout->at_y == layout->bounds.y);
18527 /* if this assert triggers you allocated space between nk_begin and nk_menubar_begin.
18528 If you want a menubar the first nuklear function after `nk_begin` has to be a
18529 `nk_menubar_begin` call. Inside the menubar you then have to allocate space for
18530 widgets (also supports multiple rows).
18531 Example:
18532 if (nk_begin(...)) {
18533 nk_menubar_begin(...);
18534 nk_layout_xxxx(...);
18535 nk_button(...);
18536 nk_layout_xxxx(...);
18537 nk_button(...);
18538 nk_menubar_end(...);
18539 }
18540 nk_end(...);
18541 */
18542 if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)
18543 return;
18544
18545 layout->menu.x = layout->at_x;
18546 layout->menu.y = layout->at_y + layout->row.height;
18547 layout->menu.w = layout->bounds.w;
18548 layout->menu.offset.x = *layout->offset_x;
18549 layout->menu.offset.y = *layout->offset_y;
18550 *layout->offset_y = 0;
18551}
18552
18553NK_API void
18554nk_menubar_end(struct nk_context *ctx)
18555{
18556 struct nk_window *win;
18557 struct nk_panel *layout;
18558 struct nk_command_buffer *out;
18559
18560 NK_ASSERT(ctx);
18561 NK_ASSERT(ctx->current);
18562 NK_ASSERT(ctx->current->layout);
18563 if (!ctx || !ctx->current || !ctx->current->layout)
18564 return;
18565
18566 win = ctx->current;
18567 out = &win->buffer;
18568 layout = win->layout;
18569 if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)
18570 return;
18571
18572 layout->menu.h = layout->at_y - layout->menu.y;
18573 layout->bounds.y += layout->menu.h + ctx->style.window.spacing.y + layout->row.height;
18574 layout->bounds.h -= layout->menu.h + ctx->style.window.spacing.y + layout->row.height;
18575
18576 *layout->offset_x = layout->menu.offset.x;
18577 *layout->offset_y = layout->menu.offset.y;
18578 layout->at_y = layout->bounds.y - layout->row.height;
18579
18580 layout->clip.y = layout->bounds.y;
18581 layout->clip.h = layout->bounds.h;
18582 nk_push_scissor(out, layout->clip);
18583}
18584/* -------------------------------------------------------------
18585 *
18586 * LAYOUT
18587 *
18588 * --------------------------------------------------------------*/
18589NK_INTERN float
18590nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type,
18591 float total_space, int columns)
18592{
18593 float panel_padding;
18594 float panel_spacing;
18595 float panel_space;
18596
18597 struct nk_vec2 spacing;
18598 struct nk_vec2 padding;
18599
18600 spacing = style->window.spacing;
18601 padding = nk_panel_get_padding(style, type);
18602
18603 /* calculate the usable panel space */
18604 panel_padding = 2 * padding.x;
18605 panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x;
18606 panel_space = total_space - panel_padding - panel_spacing;
18607 return panel_space;
18608}
18609
18610NK_INTERN void
18611nk_panel_layout(const struct nk_context *ctx, struct nk_window *win,
18612 float height, int cols)
18613{
18614 struct nk_panel *layout;
18615 const struct nk_style *style;
18616 struct nk_command_buffer *out;
18617
18618 struct nk_vec2 item_spacing;
18619 struct nk_color color;
18620
18621 NK_ASSERT(ctx);
18622 NK_ASSERT(ctx->current);
18623 NK_ASSERT(ctx->current->layout);
18624 if (!ctx || !ctx->current || !ctx->current->layout)
18625 return;
18626
18627 /* prefetch some configuration data */
18628 layout = win->layout;
18629 style = &ctx->style;
18630 out = &win->buffer;
18631 color = style->window.background;
18632 item_spacing = style->window.spacing;
18633
18634 /* if one of these triggers you forgot to add an `if` condition around either
18635 a window, group, popup, combobox or contextual menu `begin` and `end` block.
18636 Example:
18637 if (nk_begin(...) {...} nk_end(...); or
18638 if (nk_group_begin(...) { nk_group_end(...);} */
18639 NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
18640 NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
18641 NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));
18642
18643 /* update the current row and set the current row layout */
18644 layout->row.index = 0;
18645 layout->at_y += layout->row.height;
18646 layout->row.columns = cols;
18647 layout->row.height = height + item_spacing.y;
18648 layout->row.item_offset = 0;
18649 if (layout->flags & NK_WINDOW_DYNAMIC) {
18650 /* draw background for dynamic panels */
18651 struct nk_rect background;
18652 background.x = win->bounds.x;
18653 background.w = win->bounds.w;
18654 background.y = layout->at_y - 1.0f;
18655 background.h = layout->row.height + 1.0f;
18656 nk_fill_rect(out, background, 0, color);
18657 }
18658}
18659
18660NK_INTERN void
18661nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt,
18662 float height, int cols, int width)
18663{
18664 /* update the current row and set the current row layout */
18665 struct nk_window *win;
18666 NK_ASSERT(ctx);
18667 NK_ASSERT(ctx->current);
18668 NK_ASSERT(ctx->current->layout);
18669 if (!ctx || !ctx->current || !ctx->current->layout)
18670 return;
18671
18672 win = ctx->current;
18673 nk_panel_layout(ctx, win, height, cols);
18674 if (fmt == NK_DYNAMIC)
18675 win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED;
18676 else win->layout->row.type = NK_LAYOUT_STATIC_FIXED;
18677
18678 win->layout->row.ratio = 0;
18679 win->layout->row.filled = 0;
18680 win->layout->row.item_offset = 0;
18681 win->layout->row.item_width = (float)width;
18682}
18683
18684NK_API float
18685nk_layout_ratio_from_pixel(struct nk_context *ctx, float pixel_width)
18686{
18687 struct nk_window *win;
18688 NK_ASSERT(ctx);
18689 NK_ASSERT(pixel_width);
18690 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
18691 win = ctx->current;
18692 return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f);
18693}
18694
18695NK_API void
18696nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols)
18697{
18698 nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0);
18699}
18700
18701NK_API void
18702nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols)
18703{
18704 nk_row_layout(ctx, NK_STATIC, height, cols, item_width);
18705}
18706
18707NK_API void
18708nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt,
18709 float row_height, int cols)
18710{
18711 struct nk_window *win;
18712 struct nk_panel *layout;
18713
18714 NK_ASSERT(ctx);
18715 NK_ASSERT(ctx->current);
18716 NK_ASSERT(ctx->current->layout);
18717 if (!ctx || !ctx->current || !ctx->current->layout)
18718 return;
18719
18720 win = ctx->current;
18721 layout = win->layout;
18722 nk_panel_layout(ctx, win, row_height, cols);
18723 if (fmt == NK_DYNAMIC)
18724 layout->row.type = NK_LAYOUT_DYNAMIC_ROW;
18725 else layout->row.type = NK_LAYOUT_STATIC_ROW;
18726
18727 layout->row.ratio = 0;
18728 layout->row.filled = 0;
18729 layout->row.item_width = 0;
18730 layout->row.item_offset = 0;
18731 layout->row.columns = cols;
18732}
18733
18734NK_API void
18735nk_layout_row_push(struct nk_context *ctx, float ratio_or_width)
18736{
18737 struct nk_window *win;
18738 struct nk_panel *layout;
18739
18740 NK_ASSERT(ctx);
18741 NK_ASSERT(ctx->current);
18742 NK_ASSERT(ctx->current->layout);
18743 if (!ctx || !ctx->current || !ctx->current->layout)
18744 return;
18745
18746 win = ctx->current;
18747 layout = win->layout;
18748 NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
18749 if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
18750 return;
18751
18752 if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) {
18753 float ratio = ratio_or_width;
18754 if ((ratio + layout->row.filled) > 1.0f) return;
18755 if (ratio > 0.0f)
18756 layout->row.item_width = NK_SATURATE(ratio);
18757 else layout->row.item_width = 1.0f - layout->row.filled;
18758 } else layout->row.item_width = ratio_or_width;
18759}
18760
18761NK_API void
18762nk_layout_row_end(struct nk_context *ctx)
18763{
18764 struct nk_window *win;
18765 struct nk_panel *layout;
18766
18767 NK_ASSERT(ctx);
18768 NK_ASSERT(ctx->current);
18769 NK_ASSERT(ctx->current->layout);
18770 if (!ctx || !ctx->current || !ctx->current->layout)
18771 return;
18772
18773 win = ctx->current;
18774 layout = win->layout;
18775 NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
18776 if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
18777 return;
18778 layout->row.item_width = 0;
18779 layout->row.item_offset = 0;
18780}
18781
18782NK_API void
18783nk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt,
18784 float height, int cols, const float *ratio)
18785{
18786 int i;
18787 int n_undef = 0;
18788 struct nk_window *win;
18789 struct nk_panel *layout;
18790
18791 NK_ASSERT(ctx);
18792 NK_ASSERT(ctx->current);
18793 NK_ASSERT(ctx->current->layout);
18794 if (!ctx || !ctx->current || !ctx->current->layout)
18795 return;
18796
18797 win = ctx->current;
18798 layout = win->layout;
18799 nk_panel_layout(ctx, win, height, cols);
18800 if (fmt == NK_DYNAMIC) {
18801 /* calculate width of undefined widget ratios */
18802 float r = 0;
18803 layout->row.ratio = ratio;
18804 for (i = 0; i < cols; ++i) {
18805 if (ratio[i] < 0.0f)
18806 n_undef++;
18807 else r += ratio[i];
18808 }
18809 r = NK_SATURATE(1.0f - r);
18810 layout->row.type = NK_LAYOUT_DYNAMIC;
18811 layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0;
18812 } else {
18813 layout->row.ratio = ratio;
18814 layout->row.type = NK_LAYOUT_STATIC;
18815 layout->row.item_width = 0;
18816 layout->row.item_offset = 0;
18817 }
18818 layout->row.item_offset = 0;
18819 layout->row.filled = 0;
18820}
18821
18822NK_API void
18823nk_layout_row_template_begin(struct nk_context *ctx, float height)
18824{
18825 struct nk_window *win;
18826 struct nk_panel *layout;
18827
18828 NK_ASSERT(ctx);
18829 NK_ASSERT(ctx->current);
18830 NK_ASSERT(ctx->current->layout);
18831 if (!ctx || !ctx->current || !ctx->current->layout)
18832 return;
18833
18834 win = ctx->current;
18835 layout = win->layout;
18836 nk_panel_layout(ctx, win, height, 1);
18837 layout->row.type = NK_LAYOUT_TEMPLATE;
18838 layout->row.columns = 0;
18839 layout->row.ratio = 0;
18840 layout->row.item_width = 0;
18841 layout->row.item_height = 0;
18842 layout->row.item_offset = 0;
18843 layout->row.filled = 0;
18844 layout->row.item.x = 0;
18845 layout->row.item.y = 0;
18846 layout->row.item.w = 0;
18847 layout->row.item.h = 0;
18848}
18849
18850NK_API void
18851nk_layout_row_template_push_dynamic(struct nk_context *ctx)
18852{
18853 struct nk_window *win;
18854 struct nk_panel *layout;
18855
18856 NK_ASSERT(ctx);
18857 NK_ASSERT(ctx->current);
18858 NK_ASSERT(ctx->current->layout);
18859 if (!ctx || !ctx->current || !ctx->current->layout)
18860 return;
18861
18862 win = ctx->current;
18863 layout = win->layout;
18864 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
18865 NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
18866 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
18867 if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
18868 layout->row.templates[layout->row.columns++] = -1.0f;
18869}
18870
18871NK_API void
18872nk_layout_row_template_push_variable(struct nk_context *ctx, float min_width)
18873{
18874 struct nk_window *win;
18875 struct nk_panel *layout;
18876
18877 NK_ASSERT(ctx);
18878 NK_ASSERT(ctx->current);
18879 NK_ASSERT(ctx->current->layout);
18880 if (!ctx || !ctx->current || !ctx->current->layout)
18881 return;
18882
18883 win = ctx->current;
18884 layout = win->layout;
18885 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
18886 NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
18887 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
18888 if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
18889 layout->row.templates[layout->row.columns++] = -min_width;
18890}
18891
18892NK_API void
18893nk_layout_row_template_push_static(struct nk_context *ctx, float width)
18894{
18895 struct nk_window *win;
18896 struct nk_panel *layout;
18897
18898 NK_ASSERT(ctx);
18899 NK_ASSERT(ctx->current);
18900 NK_ASSERT(ctx->current->layout);
18901 if (!ctx || !ctx->current || !ctx->current->layout)
18902 return;
18903
18904 win = ctx->current;
18905 layout = win->layout;
18906 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
18907 NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
18908 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
18909 if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
18910 layout->row.templates[layout->row.columns++] = width;
18911}
18912
18913NK_API void
18914nk_layout_row_template_end(struct nk_context *ctx)
18915{
18916 struct nk_window *win;
18917 struct nk_panel *layout;
18918
18919 int i = 0;
18920 int variable_count = 0;
18921 int min_variable_count = 0;
18922 float min_fixed_width = 0.0f;
18923 float total_fixed_width = 0.0f;
18924 float max_variable_width = 0.0f;
18925
18926 NK_ASSERT(ctx);
18927 NK_ASSERT(ctx->current);
18928 NK_ASSERT(ctx->current->layout);
18929 if (!ctx || !ctx->current || !ctx->current->layout)
18930 return;
18931
18932 win = ctx->current;
18933 layout = win->layout;
18934 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
18935 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
18936 for (i = 0; i < layout->row.columns; ++i) {
18937 float width = layout->row.templates[i];
18938 if (width >= 0.0f) {
18939 total_fixed_width += width;
18940 min_fixed_width += width;
18941 } else if (width < -1.0f) {
18942 width = -width;
18943 total_fixed_width += width;
18944 max_variable_width = NK_MAX(max_variable_width, width);
18945 variable_count++;
18946 } else {
18947 min_variable_count++;
18948 variable_count++;
18949 }
18950 }
18951 if (variable_count) {
18952 float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
18953 layout->bounds.w, layout->row.columns);
18954 float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count;
18955 int enough_space = var_width >= max_variable_width;
18956 if (!enough_space)
18957 var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count;
18958 for (i = 0; i < layout->row.columns; ++i) {
18959 float *width = &layout->row.templates[i];
18960 *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width;
18961 }
18962 }
18963}
18964
18965NK_API void
18966nk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt,
18967 float height, int widget_count)
18968{
18969 struct nk_window *win;
18970 struct nk_panel *layout;
18971
18972 NK_ASSERT(ctx);
18973 NK_ASSERT(ctx->current);
18974 NK_ASSERT(ctx->current->layout);
18975 if (!ctx || !ctx->current || !ctx->current->layout)
18976 return;
18977
18978 win = ctx->current;
18979 layout = win->layout;
18980 nk_panel_layout(ctx, win, height, widget_count);
18981 if (fmt == NK_STATIC)
18982 layout->row.type = NK_LAYOUT_STATIC_FREE;
18983 else layout->row.type = NK_LAYOUT_DYNAMIC_FREE;
18984
18985 layout->row.ratio = 0;
18986 layout->row.filled = 0;
18987 layout->row.item_width = 0;
18988 layout->row.item_offset = 0;
18989}
18990
18991NK_API void
18992nk_layout_space_end(struct nk_context *ctx)
18993{
18994 struct nk_window *win;
18995 struct nk_panel *layout;
18996
18997 NK_ASSERT(ctx);
18998 NK_ASSERT(ctx->current);
18999 NK_ASSERT(ctx->current->layout);
19000 if (!ctx || !ctx->current || !ctx->current->layout)
19001 return;
19002
19003 win = ctx->current;
19004 layout = win->layout;
19005 layout->row.item_width = 0;
19006 layout->row.item_height = 0;
19007 layout->row.item_offset = 0;
19008 nk_zero(&layout->row.item, sizeof(layout->row.item));
19009}
19010
19011NK_API void
19012nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect)
19013{
19014 struct nk_window *win;
19015 struct nk_panel *layout;
19016
19017 NK_ASSERT(ctx);
19018 NK_ASSERT(ctx->current);
19019 NK_ASSERT(ctx->current->layout);
19020 if (!ctx || !ctx->current || !ctx->current->layout)
19021 return;
19022
19023 win = ctx->current;
19024 layout = win->layout;
19025 layout->row.item = rect;
19026}
19027
19028NK_API struct nk_rect
19029nk_layout_space_bounds(struct nk_context *ctx)
19030{
19031 struct nk_rect ret;
19032 struct nk_window *win;
19033 struct nk_panel *layout;
19034
19035 NK_ASSERT(ctx);
19036 NK_ASSERT(ctx->current);
19037 NK_ASSERT(ctx->current->layout);
19038 win = ctx->current;
19039 layout = win->layout;
19040
19041 ret.x = layout->clip.x;
19042 ret.y = layout->clip.y;
19043 ret.w = layout->clip.w;
19044 ret.h = layout->row.height;
19045 return ret;
19046}
19047
19048NK_API struct nk_vec2
19049nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret)
19050{
19051 struct nk_window *win;
19052 struct nk_panel *layout;
19053
19054 NK_ASSERT(ctx);
19055 NK_ASSERT(ctx->current);
19056 NK_ASSERT(ctx->current->layout);
19057 win = ctx->current;
19058 layout = win->layout;
19059
19060 ret.x += layout->at_x - (float)*layout->offset_x;
19061 ret.y += layout->at_y - (float)*layout->offset_y;
19062 return ret;
19063}
19064
19065NK_API struct nk_vec2
19066nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret)
19067{
19068 struct nk_window *win;
19069 struct nk_panel *layout;
19070
19071 NK_ASSERT(ctx);
19072 NK_ASSERT(ctx->current);
19073 NK_ASSERT(ctx->current->layout);
19074 win = ctx->current;
19075 layout = win->layout;
19076
19077 ret.x += -layout->at_x + (float)*layout->offset_x;
19078 ret.y += -layout->at_y + (float)*layout->offset_y;
19079 return ret;
19080}
19081
19082NK_API struct nk_rect
19083nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret)
19084{
19085 struct nk_window *win;
19086 struct nk_panel *layout;
19087
19088 NK_ASSERT(ctx);
19089 NK_ASSERT(ctx->current);
19090 NK_ASSERT(ctx->current->layout);
19091 win = ctx->current;
19092 layout = win->layout;
19093
19094 ret.x += layout->at_x - (float)*layout->offset_x;
19095 ret.y += layout->at_y - (float)*layout->offset_y;
19096 return ret;
19097}
19098
19099NK_API struct nk_rect
19100nk_layout_space_rect_to_local(struct nk_context *ctx, struct nk_rect ret)
19101{
19102 struct nk_window *win;
19103 struct nk_panel *layout;
19104
19105 NK_ASSERT(ctx);
19106 NK_ASSERT(ctx->current);
19107 NK_ASSERT(ctx->current->layout);
19108 win = ctx->current;
19109 layout = win->layout;
19110
19111 ret.x += -layout->at_x + (float)*layout->offset_x;
19112 ret.y += -layout->at_y + (float)*layout->offset_y;
19113 return ret;
19114}
19115
19116NK_INTERN void
19117nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win)
19118{
19119 struct nk_panel *layout = win->layout;
19120 struct nk_vec2 spacing = ctx->style.window.spacing;
19121 const float row_height = layout->row.height - spacing.y;
19122 nk_panel_layout(ctx, win, row_height, layout->row.columns);
19123}
19124
19125NK_INTERN void
19126nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx,
19127 struct nk_window *win, int modify)
19128{
19129 struct nk_panel *layout;
19130 const struct nk_style *style;
19131
19132 struct nk_vec2 spacing;
19133 struct nk_vec2 padding;
19134
19135 float item_offset = 0;
19136 float item_width = 0;
19137 float item_spacing = 0;
19138 float panel_space = 0;
19139
19140 NK_ASSERT(ctx);
19141 NK_ASSERT(ctx->current);
19142 NK_ASSERT(ctx->current->layout);
19143 if (!ctx || !ctx->current || !ctx->current->layout)
19144 return;
19145
19146 win = ctx->current;
19147 layout = win->layout;
19148 style = &ctx->style;
19149 NK_ASSERT(bounds);
19150
19151 spacing = style->window.spacing;
19152 padding = nk_panel_get_padding(style, layout->type);
19153 panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
19154 layout->bounds.w, layout->row.columns);
19155
19156 /* calculate the width of one item inside the current layout space */
19157 switch (layout->row.type) {
19158 case NK_LAYOUT_DYNAMIC_FIXED: {
19159 /* scaling fixed size widgets item width */
19160 item_width = panel_space / (float)layout->row.columns;
19161 item_offset = (float)layout->row.index * item_width;
19162 item_spacing = (float)layout->row.index * spacing.x;
19163 } break;
19164 case NK_LAYOUT_DYNAMIC_ROW: {
19165 /* scaling single ratio widget width */
19166 item_width = layout->row.item_width * panel_space;
19167 item_offset = layout->row.item_offset;
19168 item_spacing = 0;
19169
19170 if (modify) {
19171 layout->row.item_offset += item_width + spacing.x;
19172 layout->row.filled += layout->row.item_width;
19173 layout->row.index = 0;
19174 }
19175 } break;
19176 case NK_LAYOUT_DYNAMIC_FREE: {
19177 /* panel width depended free widget placing */
19178 bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x);
19179 bounds->x -= (float)*layout->offset_x;
19180 bounds->y = layout->at_y + (layout->row.height * layout->row.item.y);
19181 bounds->y -= (float)*layout->offset_y;
19182 bounds->w = layout->bounds.w * layout->row.item.w;
19183 bounds->h = layout->row.height * layout->row.item.h;
19184 return;
19185 } break;
19186 case NK_LAYOUT_DYNAMIC: {
19187 /* scaling arrays of panel width ratios for every widget */
19188 float ratio;
19189 NK_ASSERT(layout->row.ratio);
19190 ratio = (layout->row.ratio[layout->row.index] < 0) ?
19191 layout->row.item_width : layout->row.ratio[layout->row.index];
19192
19193 item_spacing = (float)layout->row.index * spacing.x;
19194 item_width = (ratio * panel_space);
19195 item_offset = layout->row.item_offset;
19196
19197 if (modify) {
19198 layout->row.item_offset += item_width;
19199 layout->row.filled += ratio;
19200 }
19201 } break;
19202 case NK_LAYOUT_STATIC_FIXED: {
19203 /* non-scaling fixed widgets item width */
19204 item_width = layout->row.item_width;
19205 item_offset = (float)layout->row.index * item_width;
19206 item_spacing = (float)layout->row.index * spacing.x;
19207 } break;
19208 case NK_LAYOUT_STATIC_ROW: {
19209 /* scaling single ratio widget width */
19210 item_width = layout->row.item_width;
19211 item_offset = layout->row.item_offset;
19212 item_spacing = (float)layout->row.index * spacing.x;
19213 if (modify) layout->row.item_offset += item_width;
19214 } break;
19215 case NK_LAYOUT_STATIC_FREE: {
19216 /* free widget placing */
19217 bounds->x = layout->at_x + layout->row.item.x;
19218 bounds->w = layout->row.item.w;
19219 if (((bounds->x + bounds->w) > layout->max_x) && modify)
19220 layout->max_x = (bounds->x + bounds->w);
19221 bounds->x -= (float)*layout->offset_x;
19222 bounds->y = layout->at_y + layout->row.item.y;
19223 bounds->y -= (float)*layout->offset_y;
19224 bounds->h = layout->row.item.h;
19225 return;
19226 } break;
19227 case NK_LAYOUT_STATIC: {
19228 /* non-scaling array of panel pixel width for every widget */
19229 item_spacing = (float)layout->row.index * spacing.x;
19230 item_width = layout->row.ratio[layout->row.index];
19231 item_offset = layout->row.item_offset;
19232 if (modify) layout->row.item_offset += item_width;
19233 } break;
19234 case NK_LAYOUT_TEMPLATE: {
19235 /* stretchy row layout with combined dynamic/static widget width*/
19236 NK_ASSERT(layout->row.index < layout->row.columns);
19237 NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
19238 item_width = layout->row.templates[layout->row.index];
19239 item_offset = layout->row.item_offset;
19240 item_spacing = (float)layout->row.index * spacing.x;
19241 if (modify) layout->row.item_offset += item_width;
19242 } break;
19243 default: NK_ASSERT(0); break;
19244 };
19245
19246 /* set the bounds of the newly allocated widget */
19247 bounds->w = item_width;
19248 bounds->h = layout->row.height - spacing.y;
19249 bounds->y = layout->at_y - (float)*layout->offset_y;
19250 bounds->x = layout->at_x + item_offset + item_spacing + padding.x;
19251 if (((bounds->x + bounds->w) > layout->max_x) && modify)
19252 layout->max_x = bounds->x + bounds->w;
19253 bounds->x -= (float)*layout->offset_x;
19254}
19255
19256NK_INTERN void
19257nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx)
19258{
19259 struct nk_window *win;
19260 struct nk_panel *layout;
19261
19262 NK_ASSERT(ctx);
19263 NK_ASSERT(ctx->current);
19264 NK_ASSERT(ctx->current->layout);
19265 if (!ctx || !ctx->current || !ctx->current->layout)
19266 return;
19267
19268 /* check if the end of the row has been hit and begin new row if so */
19269 win = ctx->current;
19270 layout = win->layout;
19271 if (layout->row.index >= layout->row.columns)
19272 nk_panel_alloc_row(ctx, win);
19273
19274 /* calculate widget position and size */
19275 nk_layout_widget_space(bounds, ctx, win, nk_true);
19276 layout->row.index++;
19277}
19278
19279NK_INTERN void
19280nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx)
19281{
19282 float y;
19283 int index;
19284 struct nk_window *win;
19285 struct nk_panel *layout;
19286
19287 NK_ASSERT(ctx);
19288 NK_ASSERT(ctx->current);
19289 NK_ASSERT(ctx->current->layout);
19290 if (!ctx || !ctx->current || !ctx->current->layout)
19291 return;
19292
19293 win = ctx->current;
19294 layout = win->layout;
19295 y = layout->at_y;
19296 index = layout->row.index;
19297 if (layout->row.index >= layout->row.columns) {
19298 layout->at_y += layout->row.height;
19299 layout->row.index = 0;
19300 }
19301 nk_layout_widget_space(bounds, ctx, win, nk_false);
19302 layout->at_y = y;
19303 layout->row.index = index;
19304}
19305
19306NK_INTERN int
19307nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type,
19308 struct nk_image *img, const char *title, enum nk_collapse_states *state)
19309{
19310 struct nk_window *win;
19311 struct nk_panel *layout;
19312 const struct nk_style *style;
19313 struct nk_command_buffer *out;
19314 const struct nk_input *in;
19315 const struct nk_style_button *button;
19316 enum nk_symbol_type symbol;
19317
19318 struct nk_vec2 item_spacing;
19319 struct nk_rect header = {0,0,0,0};
19320 struct nk_rect sym = {0,0,0,0};
19321 struct nk_text text;
19322
19323 nk_flags ws = 0;
19324 enum nk_widget_layout_states widget_state;
19325
19326 NK_ASSERT(ctx);
19327 NK_ASSERT(ctx->current);
19328 NK_ASSERT(ctx->current->layout);
19329 if (!ctx || !ctx->current || !ctx->current->layout)
19330 return 0;
19331
19332 /* cache some data */
19333 win = ctx->current;
19334 layout = win->layout;
19335 out = &win->buffer;
19336 style = &ctx->style;
19337 item_spacing = style->window.spacing;
19338
19339 /* calculate header bounds and draw background */
19340 nk_layout_row_dynamic(ctx, style->font->height + 2 * style->tab.padding.y, 1);
19341 widget_state = nk_widget(&header, ctx);
19342 if (type == NK_TREE_TAB) {
19343 const struct nk_style_item *background = &style->tab.background;
19344 if (background->type == NK_STYLE_ITEM_IMAGE) {
19345 nk_draw_image(out, header, &background->data.image, nk_white);
19346 text.background = nk_rgba(0,0,0,0);
19347 } else {
19348 text.background = background->data.color;
19349 nk_fill_rect(out, header, 0, style->tab.border_color);
19350 nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),
19351 style->tab.rounding, background->data.color);
19352 }
19353 } else text.background = style->window.background;
19354
19355 /* update node state */
19356 in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;
19357 in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;
19358 if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT))
19359 *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;
19360
19361 /* select correct button style */
19362 if (*state == NK_MAXIMIZED) {
19363 symbol = style->tab.sym_maximize;
19364 if (type == NK_TREE_TAB)
19365 button = &style->tab.tab_maximize_button;
19366 else button = &style->tab.node_maximize_button;
19367 } else {
19368 symbol = style->tab.sym_minimize;
19369 if (type == NK_TREE_TAB)
19370 button = &style->tab.tab_minimize_button;
19371 else button = &style->tab.node_minimize_button;
19372 }
19373
19374 {/* draw triangle button */
19375 sym.w = sym.h = style->font->height;
19376 sym.y = header.y + style->tab.padding.y;
19377 sym.x = header.x + style->tab.padding.x;
19378 nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT,
19379 button, 0, style->font);
19380
19381 if (img) {
19382 /* draw optional image icon */
19383 sym.x = sym.x + sym.w + 4 * item_spacing.x;
19384 nk_draw_image(&win->buffer, sym, img, nk_white);
19385 sym.w = style->font->height + style->tab.spacing.x;}
19386 }
19387
19388 {/* draw label */
19389 struct nk_rect label;
19390 header.w = NK_MAX(header.w, sym.w + item_spacing.x);
19391 label.x = sym.x + sym.w + item_spacing.x;
19392 label.y = sym.y;
19393 label.w = header.w - (sym.w + item_spacing.y + style->tab.indent);
19394 label.h = style->font->height;
19395 text.text = style->tab.text;
19396 text.padding = nk_vec2(0,0);
19397 nk_widget_text(out, label, title, nk_strlen(title), &text,
19398 NK_TEXT_LEFT, style->font);}
19399
19400 /* increase x-axis cursor widget position pointer */
19401 if (*state == NK_MAXIMIZED) {
19402 layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;
19403 layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);
19404 layout->bounds.w -= (style->tab.indent + style->window.padding.x);
19405 layout->row.tree_depth++;
19406 return nk_true;
19407 } else return nk_false;
19408}
19409
19410NK_INTERN int
19411nk_tree_base(struct nk_context *ctx, enum nk_tree_type type,
19412 struct nk_image *img, const char *title, enum nk_collapse_states initial_state,
19413 const char *hash, int len, int line)
19414{
19415 struct nk_window *win = ctx->current;
19416 int title_len = 0;
19417 nk_hash tree_hash = 0;
19418 nk_uint *state = 0;
19419
19420 /* retrieve tree state from internal widget state tables */
19421 if (!hash) {
19422 title_len = (int)nk_strlen(title);
19423 tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);
19424 } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);
19425 state = nk_find_value(win, tree_hash);
19426 if (!state) {
19427 state = nk_add_value(ctx, win, tree_hash, 0);
19428 *state = initial_state;
19429 }
19430 return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state);
19431}
19432
19433NK_API int
19434nk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type,
19435 const char *title, enum nk_collapse_states *state)
19436{return nk_tree_state_base(ctx, type, 0, title, state);}
19437
19438NK_API int
19439nk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type,
19440 struct nk_image img, const char *title, enum nk_collapse_states *state)
19441{return nk_tree_state_base(ctx, type, &img, title, state);}
19442
19443NK_API void
19444nk_tree_state_pop(struct nk_context *ctx)
19445{
19446 struct nk_window *win = 0;
19447 struct nk_panel *layout = 0;
19448
19449 NK_ASSERT(ctx);
19450 NK_ASSERT(ctx->current);
19451 NK_ASSERT(ctx->current->layout);
19452 if (!ctx || !ctx->current || !ctx->current->layout)
19453 return;
19454
19455 win = ctx->current;
19456 layout = win->layout;
19457 layout->at_x -= ctx->style.tab.indent + ctx->style.window.padding.x;
19458 layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x;
19459 NK_ASSERT(layout->row.tree_depth);
19460 layout->row.tree_depth--;
19461}
19462
19463NK_API int
19464nk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
19465 const char *title, enum nk_collapse_states initial_state,
19466 const char *hash, int len, int line)
19467{return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);}
19468
19469NK_API int
19470nk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
19471 struct nk_image img, const char *title, enum nk_collapse_states initial_state,
19472 const char *hash, int len,int seed)
19473{return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);}
19474
19475NK_API void
19476nk_tree_pop(struct nk_context *ctx)
19477{nk_tree_state_pop(ctx);}
19478
19479/*----------------------------------------------------------------
19480 *
19481 * WIDGETS
19482 *
19483 * --------------------------------------------------------------*/
19484NK_API struct nk_rect
19485nk_widget_bounds(struct nk_context *ctx)
19486{
19487 struct nk_rect bounds;
19488 NK_ASSERT(ctx);
19489 NK_ASSERT(ctx->current);
19490 if (!ctx || !ctx->current)
19491 return nk_rect(0,0,0,0);
19492 nk_layout_peek(&bounds, ctx);
19493 return bounds;
19494}
19495
19496NK_API struct nk_vec2
19497nk_widget_position(struct nk_context *ctx)
19498{
19499 struct nk_rect bounds;
19500 NK_ASSERT(ctx);
19501 NK_ASSERT(ctx->current);
19502 if (!ctx || !ctx->current)
19503 return nk_vec2(0,0);
19504
19505 nk_layout_peek(&bounds, ctx);
19506 return nk_vec2(bounds.x, bounds.y);
19507}
19508
19509NK_API struct nk_vec2
19510nk_widget_size(struct nk_context *ctx)
19511{
19512 struct nk_rect bounds;
19513 NK_ASSERT(ctx);
19514 NK_ASSERT(ctx->current);
19515 if (!ctx || !ctx->current)
19516 return nk_vec2(0,0);
19517
19518 nk_layout_peek(&bounds, ctx);
19519 return nk_vec2(bounds.w, bounds.h);
19520}
19521
19522NK_API float
19523nk_widget_width(struct nk_context *ctx)
19524{
19525 struct nk_rect bounds;
19526 NK_ASSERT(ctx);
19527 NK_ASSERT(ctx->current);
19528 if (!ctx || !ctx->current)
19529 return 0;
19530
19531 nk_layout_peek(&bounds, ctx);
19532 return bounds.w;
19533}
19534
19535NK_API float
19536nk_widget_height(struct nk_context *ctx)
19537{
19538 struct nk_rect bounds;
19539 NK_ASSERT(ctx);
19540 NK_ASSERT(ctx->current);
19541 if (!ctx || !ctx->current)
19542 return 0;
19543
19544 nk_layout_peek(&bounds, ctx);
19545 return bounds.h;
19546}
19547
19548NK_API int
19549nk_widget_is_hovered(struct nk_context *ctx)
19550{
19551 int ret;
19552 struct nk_rect bounds;
19553 NK_ASSERT(ctx);
19554 NK_ASSERT(ctx->current);
19555 if (!ctx || !ctx->current)
19556 return 0;
19557
19558 nk_layout_peek(&bounds, ctx);
19559 ret = (ctx->active == ctx->current);
19560 ret = ret && nk_input_is_mouse_hovering_rect(&ctx->input, bounds);
19561 return ret;
19562}
19563
19564NK_API int
19565nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn)
19566{
19567 int ret;
19568 struct nk_rect bounds;
19569 NK_ASSERT(ctx);
19570 NK_ASSERT(ctx->current);
19571 if (!ctx || !ctx->current)
19572 return 0;
19573
19574 nk_layout_peek(&bounds, ctx);
19575 ret = (ctx->active == ctx->current);
19576 ret = ret && nk_input_mouse_clicked(&ctx->input, btn, bounds);
19577 return ret;
19578}
19579
19580NK_API int
19581nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, int down)
19582{
19583 int ret;
19584 struct nk_rect bounds;
19585 NK_ASSERT(ctx);
19586 NK_ASSERT(ctx->current);
19587 if (!ctx || !ctx->current)
19588 return 0;
19589
19590 nk_layout_peek(&bounds, ctx);
19591 ret = (ctx->active == ctx->current);
19592 ret = ret && nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down);
19593 return ret;
19594}
19595
19596NK_API enum nk_widget_layout_states
19597nk_widget(struct nk_rect *bounds, const struct nk_context *ctx)
19598{
19599 struct nk_rect c;
19600 struct nk_window *win;
19601 struct nk_panel *layout;
19602
19603 NK_ASSERT(ctx);
19604 NK_ASSERT(ctx->current);
19605 NK_ASSERT(ctx->current->layout);
19606 if (!ctx || !ctx->current || !ctx->current->layout)
19607 return NK_WIDGET_INVALID;
19608
19609 /* allocate space and check if the widget needs to be updated and drawn */
19610 nk_panel_alloc_space(bounds, ctx);
19611 win = ctx->current;
19612 layout = win->layout;
19613 c = layout->clip;
19614
19615 /* if one of these triggers you forgot to add an `if` condition around either
19616 a window, group, popup, combobox or contextual menu `begin` and `end` block.
19617 Example:
19618 if (nk_begin(...) {...} nk_end(...); or
19619 if (nk_group_begin(...) { nk_group_end(...);} */
19620 NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
19621 NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
19622 NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));
19623
19624 /* need to convert to int here to remove floating point errors */
19625 bounds->x = (float)((int)bounds->x);
19626 bounds->y = (float)((int)bounds->y);
19627 bounds->w = (float)((int)bounds->w);
19628 bounds->h = (float)((int)bounds->h);
19629
19630 c.x = (float)((int)c.x);
19631 c.y = (float)((int)c.y);
19632 c.w = (float)((int)c.w);
19633 c.h = (float)((int)c.h);
19634
19635 if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h))
19636 return NK_WIDGET_INVALID;
19637 if (!NK_CONTAINS(bounds->x, bounds->y, bounds->w, bounds->h, c.x, c.y, c.w, c.h))
19638 return NK_WIDGET_ROM;
19639 return NK_WIDGET_VALID;
19640}
19641
19642NK_API enum nk_widget_layout_states
19643nk_widget_fitting(struct nk_rect *bounds, struct nk_context *ctx,
19644 struct nk_vec2 item_padding)
19645{
19646 /* update the bounds to stand without padding */
19647 struct nk_window *win;
19648 struct nk_style *style;
19649 struct nk_panel *layout;
19650 enum nk_widget_layout_states state;
19651 struct nk_vec2 panel_padding;
19652
19653 NK_ASSERT(ctx);
19654 NK_ASSERT(ctx->current);
19655 NK_ASSERT(ctx->current->layout);
19656 if (!ctx || !ctx->current || !ctx->current->layout)
19657 return NK_WIDGET_INVALID;
19658
19659 win = ctx->current;
19660 style = &ctx->style;
19661 layout = win->layout;
19662 state = nk_widget(bounds, ctx);
19663
19664 panel_padding = nk_panel_get_padding(style, layout->type);
19665 if (layout->row.index == 1) {
19666 bounds->w += panel_padding.x;
19667 bounds->x -= panel_padding.x;
19668 } else bounds->x -= item_padding.x;
19669
19670 if (layout->row.index == layout->row.columns)
19671 bounds->w += panel_padding.x;
19672 else bounds->w += item_padding.x;
19673 return state;
19674}
19675
19676/*----------------------------------------------------------------
19677 *
19678 * MISC
19679 *
19680 * --------------------------------------------------------------*/
19681NK_API void
19682nk_spacing(struct nk_context *ctx, int cols)
19683{
19684 struct nk_window *win;
19685 struct nk_panel *layout;
19686 struct nk_rect none;
19687 int i, index, rows;
19688
19689 NK_ASSERT(ctx);
19690 NK_ASSERT(ctx->current);
19691 NK_ASSERT(ctx->current->layout);
19692 if (!ctx || !ctx->current || !ctx->current->layout)
19693 return;
19694
19695 /* spacing over row boundaries */
19696 win = ctx->current;
19697 layout = win->layout;
19698 index = (layout->row.index + cols) % layout->row.columns;
19699 rows = (layout->row.index + cols) / layout->row.columns;
19700 if (rows) {
19701 for (i = 0; i < rows; ++i)
19702 nk_panel_alloc_row(ctx, win);
19703 cols = index;
19704 }
19705
19706 /* non table layout need to allocate space */
19707 if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED &&
19708 layout->row.type != NK_LAYOUT_STATIC_FIXED) {
19709 for (i = 0; i < cols; ++i)
19710 nk_panel_alloc_space(&none, ctx);
19711 }
19712 layout->row.index = index;
19713}
19714
19715/*----------------------------------------------------------------
19716 *
19717 * TEXT
19718 *
19719 * --------------------------------------------------------------*/
19720NK_API void
19721nk_text_colored(struct nk_context *ctx, const char *str, int len,
19722 nk_flags alignment, struct nk_color color)
19723{
19724 struct nk_window *win;
19725 const struct nk_style *style;
19726
19727 struct nk_vec2 item_padding;
19728 struct nk_rect bounds;
19729 struct nk_text text;
19730
19731 NK_ASSERT(ctx);
19732 NK_ASSERT(ctx->current);
19733 NK_ASSERT(ctx->current->layout);
19734 if (!ctx || !ctx->current || !ctx->current->layout) return;
19735
19736 win = ctx->current;
19737 style = &ctx->style;
19738 nk_panel_alloc_space(&bounds, ctx);
19739 item_padding = style->text.padding;
19740
19741 text.padding.x = item_padding.x;
19742 text.padding.y = item_padding.y;
19743 text.background = style->window.background;
19744 text.text = color;
19745 nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font);
19746}
19747
19748NK_API void
19749nk_text_wrap_colored(struct nk_context *ctx, const char *str,
19750 int len, struct nk_color color)
19751{
19752 struct nk_window *win;
19753 const struct nk_style *style;
19754
19755 struct nk_vec2 item_padding;
19756 struct nk_rect bounds;
19757 struct nk_text text;
19758
19759 NK_ASSERT(ctx);
19760 NK_ASSERT(ctx->current);
19761 NK_ASSERT(ctx->current->layout);
19762 if (!ctx || !ctx->current || !ctx->current->layout) return;
19763
19764 win = ctx->current;
19765 style = &ctx->style;
19766 nk_panel_alloc_space(&bounds, ctx);
19767 item_padding = style->text.padding;
19768
19769 text.padding.x = item_padding.x;
19770 text.padding.y = item_padding.y;
19771 text.background = style->window.background;
19772 text.text = color;
19773 nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font);
19774}
19775
19776#ifdef NK_INCLUDE_STANDARD_VARARGS
19777NK_API void
19778nk_labelf_colored(struct nk_context *ctx, nk_flags flags,
19779 struct nk_color color, const char *fmt, ...)
19780{
19781 char buf[256];
19782 va_list args;
19783 va_start(args, fmt);
19784 nk_strfmt(buf, NK_LEN(buf), fmt, args);
19785 nk_label_colored(ctx, buf, flags, color);
19786 va_end(args);
19787}
19788
19789NK_API void
19790nk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color,
19791 const char *fmt, ...)
19792{
19793 char buf[256];
19794 va_list args;
19795 va_start(args, fmt);
19796 nk_strfmt(buf, NK_LEN(buf), fmt, args);
19797 nk_label_colored_wrap(ctx, buf, color);
19798 va_end(args);
19799}
19800
19801NK_API void
19802nk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...)
19803{
19804 char buf[256];
19805 va_list args;
19806 va_start(args, fmt);
19807 nk_strfmt(buf, NK_LEN(buf), fmt, args);
19808 nk_label(ctx, buf, flags);
19809 va_end(args);
19810}
19811
19812NK_API void
19813nk_labelf_wrap(struct nk_context *ctx, const char *fmt,...)
19814{
19815 char buf[256];
19816 va_list args;
19817 va_start(args, fmt);
19818 nk_strfmt(buf, NK_LEN(buf), fmt, args);
19819 nk_label_wrap(ctx, buf);
19820 va_end(args);
19821}
19822
19823NK_API void
19824nk_value_bool(struct nk_context *ctx, const char *prefix, int value)
19825{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, ((value) ? "true": "false"));}
19826
19827NK_API void
19828nk_value_int(struct nk_context *ctx, const char *prefix, int value)
19829{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %d", prefix, value);}
19830
19831NK_API void
19832nk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value)
19833{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %u", prefix, value);}
19834
19835NK_API void
19836nk_value_float(struct nk_context *ctx, const char *prefix, float value)
19837{
19838 double double_value = (double)value;
19839 nk_labelf(ctx, NK_TEXT_LEFT, "%s: %.3f", prefix, double_value);
19840}
19841
19842NK_API void
19843nk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c)
19844{nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%d, %d, %d, %d)", p, c.r, c.g, c.b, c.a);}
19845
19846NK_API void
19847nk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color)
19848{
19849 double c[4]; nk_color_dv(c, color);
19850 nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%.2f, %.2f, %.2f, %.2f)",
19851 p, c[0], c[1], c[2], c[3]);
19852}
19853
19854NK_API void
19855nk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color)
19856{
19857 char hex[16];
19858 nk_color_hex_rgba(hex, color);
19859 nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, hex);
19860}
19861#endif
19862
19863NK_API void
19864nk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment)
19865{
19866 NK_ASSERT(ctx);
19867 if (!ctx) return;
19868 nk_text_colored(ctx, str, len, alignment, ctx->style.text.color);
19869}
19870
19871NK_API void
19872nk_text_wrap(struct nk_context *ctx, const char *str, int len)
19873{
19874 NK_ASSERT(ctx);
19875 if (!ctx) return;
19876 nk_text_wrap_colored(ctx, str, len, ctx->style.text.color);
19877}
19878
19879NK_API void
19880nk_label(struct nk_context *ctx, const char *str, nk_flags alignment)
19881{nk_text(ctx, str, nk_strlen(str), alignment);}
19882
19883NK_API void
19884nk_label_colored(struct nk_context *ctx, const char *str, nk_flags align,
19885 struct nk_color color)
19886{nk_text_colored(ctx, str, nk_strlen(str), align, color);}
19887
19888NK_API void
19889nk_label_wrap(struct nk_context *ctx, const char *str)
19890{nk_text_wrap(ctx, str, nk_strlen(str));}
19891
19892NK_API void
19893nk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color)
19894{nk_text_wrap_colored(ctx, str, nk_strlen(str), color);}
19895
19896NK_API void
19897nk_image(struct nk_context *ctx, struct nk_image img)
19898{
19899 struct nk_window *win;
19900 struct nk_rect bounds;
19901
19902 NK_ASSERT(ctx);
19903 NK_ASSERT(ctx->current);
19904 NK_ASSERT(ctx->current->layout);
19905 if (!ctx || !ctx->current || !ctx->current->layout) return;
19906
19907 win = ctx->current;
19908 if (!nk_widget(&bounds, ctx)) return;
19909 nk_draw_image(&win->buffer, bounds, &img, nk_white);
19910}
19911
19912/*----------------------------------------------------------------
19913 *
19914 * BUTTON
19915 *
19916 * --------------------------------------------------------------*/
19917NK_API void
19918nk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)
19919{
19920 NK_ASSERT(ctx);
19921 if (!ctx) return;
19922 ctx->button_behavior = behavior;
19923}
19924
19925NK_API int
19926nk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)
19927{
19928 struct nk_config_stack_button_behavior *button_stack;
19929 struct nk_config_stack_button_behavior_element *element;
19930
19931 NK_ASSERT(ctx);
19932 if (!ctx) return 0;
19933
19934 button_stack = &ctx->stacks.button_behaviors;
19935 NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements));
19936 if (button_stack->head >= (int)NK_LEN(button_stack->elements))
19937 return 0;
19938
19939 element = &button_stack->elements[button_stack->head++];
19940 element->address = &ctx->button_behavior;
19941 element->old_value = ctx->button_behavior;
19942 ctx->button_behavior = behavior;
19943 return 1;
19944}
19945
19946NK_API int
19947nk_button_pop_behavior(struct nk_context *ctx)
19948{
19949 struct nk_config_stack_button_behavior *button_stack;
19950 struct nk_config_stack_button_behavior_element *element;
19951
19952 NK_ASSERT(ctx);
19953 if (!ctx) return 0;
19954
19955 button_stack = &ctx->stacks.button_behaviors;
19956 NK_ASSERT(button_stack->head > 0);
19957 if (button_stack->head < 1)
19958 return 0;
19959
19960 element = &button_stack->elements[--button_stack->head];
19961 *element->address = element->old_value;
19962 return 1;
19963}
19964
19965NK_API int
19966nk_button_text_styled(struct nk_context *ctx,
19967 const struct nk_style_button *style, const char *title, int len)
19968{
19969 struct nk_window *win;
19970 struct nk_panel *layout;
19971 const struct nk_input *in;
19972
19973 struct nk_rect bounds;
19974 enum nk_widget_layout_states state;
19975
19976 NK_ASSERT(ctx);
19977 NK_ASSERT(style);
19978 NK_ASSERT(ctx->current);
19979 NK_ASSERT(ctx->current->layout);
19980 if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0;
19981
19982 win = ctx->current;
19983 layout = win->layout;
19984 state = nk_widget(&bounds, ctx);
19985
19986 if (!state) return 0;
19987 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
19988 return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,
19989 title, len, style->text_alignment, ctx->button_behavior,
19990 style, in, ctx->style.font);
19991}
19992
19993NK_API int
19994nk_button_text(struct nk_context *ctx, const char *title, int len)
19995{
19996 NK_ASSERT(ctx);
19997 if (!ctx) return 0;
19998 return nk_button_text_styled(ctx, &ctx->style.button, title, len);
19999}
20000
20001NK_API int nk_button_label_styled(struct nk_context *ctx,
20002 const struct nk_style_button *style, const char *title)
20003{return nk_button_text_styled(ctx, style, title, nk_strlen(title));}
20004
20005NK_API int nk_button_label(struct nk_context *ctx, const char *title)
20006{return nk_button_text(ctx, title, nk_strlen(title));}
20007
20008NK_API int
20009nk_button_color(struct nk_context *ctx, struct nk_color color)
20010{
20011 struct nk_window *win;
20012 struct nk_panel *layout;
20013 const struct nk_input *in;
20014 struct nk_style_button button;
20015
20016 int ret = 0;
20017 struct nk_rect bounds;
20018 struct nk_rect content;
20019 enum nk_widget_layout_states state;
20020
20021 NK_ASSERT(ctx);
20022 NK_ASSERT(ctx->current);
20023 NK_ASSERT(ctx->current->layout);
20024 if (!ctx || !ctx->current || !ctx->current->layout)
20025 return 0;
20026
20027 win = ctx->current;
20028 layout = win->layout;
20029
20030 state = nk_widget(&bounds, ctx);
20031 if (!state) return 0;
20032 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20033
20034 button = ctx->style.button;
20035 button.normal = nk_style_item_color(color);
20036 button.hover = nk_style_item_color(color);
20037 button.active = nk_style_item_color(color);
20038 ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds,
20039 &button, in, ctx->button_behavior, &content);
20040 nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button);
20041 return ret;
20042}
20043
20044NK_API int
20045nk_button_symbol_styled(struct nk_context *ctx,
20046 const struct nk_style_button *style, enum nk_symbol_type symbol)
20047{
20048 struct nk_window *win;
20049 struct nk_panel *layout;
20050 const struct nk_input *in;
20051
20052 struct nk_rect bounds;
20053 enum nk_widget_layout_states state;
20054
20055 NK_ASSERT(ctx);
20056 NK_ASSERT(ctx->current);
20057 NK_ASSERT(ctx->current->layout);
20058 if (!ctx || !ctx->current || !ctx->current->layout)
20059 return 0;
20060
20061 win = ctx->current;
20062 layout = win->layout;
20063 state = nk_widget(&bounds, ctx);
20064 if (!state) return 0;
20065 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20066 return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds,
20067 symbol, ctx->button_behavior, style, in, ctx->style.font);
20068}
20069
20070NK_API int
20071nk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol)
20072{
20073 NK_ASSERT(ctx);
20074 if (!ctx) return 0;
20075 return nk_button_symbol_styled(ctx, &ctx->style.button, symbol);
20076}
20077
20078NK_API int
20079nk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style,
20080 struct nk_image img)
20081{
20082 struct nk_window *win;
20083 struct nk_panel *layout;
20084 const struct nk_input *in;
20085
20086 struct nk_rect bounds;
20087 enum nk_widget_layout_states state;
20088
20089 NK_ASSERT(ctx);
20090 NK_ASSERT(ctx->current);
20091 NK_ASSERT(ctx->current->layout);
20092 if (!ctx || !ctx->current || !ctx->current->layout)
20093 return 0;
20094
20095 win = ctx->current;
20096 layout = win->layout;
20097
20098 state = nk_widget(&bounds, ctx);
20099 if (!state) return 0;
20100 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20101 return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds,
20102 img, ctx->button_behavior, style, in);
20103}
20104
20105NK_API int
20106nk_button_image(struct nk_context *ctx, struct nk_image img)
20107{
20108 NK_ASSERT(ctx);
20109 if (!ctx) return 0;
20110 return nk_button_image_styled(ctx, &ctx->style.button, img);
20111}
20112
20113NK_API int
20114nk_button_symbol_text_styled(struct nk_context *ctx,
20115 const struct nk_style_button *style, enum nk_symbol_type symbol,
20116 const char *text, int len, nk_flags align)
20117{
20118 struct nk_window *win;
20119 struct nk_panel *layout;
20120 const struct nk_input *in;
20121
20122 struct nk_rect bounds;
20123 enum nk_widget_layout_states state;
20124
20125 NK_ASSERT(ctx);
20126 NK_ASSERT(ctx->current);
20127 NK_ASSERT(ctx->current->layout);
20128 if (!ctx || !ctx->current || !ctx->current->layout)
20129 return 0;
20130
20131 win = ctx->current;
20132 layout = win->layout;
20133
20134 state = nk_widget(&bounds, ctx);
20135 if (!state) return 0;
20136 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20137 return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,
20138 symbol, text, len, align, ctx->button_behavior,
20139 style, ctx->style.font, in);
20140}
20141
20142NK_API int
20143nk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,
20144 const char* text, int len, nk_flags align)
20145{
20146 NK_ASSERT(ctx);
20147 if (!ctx) return 0;
20148 return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align);
20149}
20150
20151NK_API int nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,
20152 const char *label, nk_flags align)
20153{return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align);}
20154
20155NK_API int nk_button_symbol_label_styled(struct nk_context *ctx,
20156 const struct nk_style_button *style, enum nk_symbol_type symbol,
20157 const char *title, nk_flags align)
20158{return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align);}
20159
20160NK_API int
20161nk_button_image_text_styled(struct nk_context *ctx,
20162 const struct nk_style_button *style, struct nk_image img, const char *text,
20163 int len, nk_flags align)
20164{
20165 struct nk_window *win;
20166 struct nk_panel *layout;
20167 const struct nk_input *in;
20168
20169 struct nk_rect bounds;
20170 enum nk_widget_layout_states state;
20171
20172 NK_ASSERT(ctx);
20173 NK_ASSERT(ctx->current);
20174 NK_ASSERT(ctx->current->layout);
20175 if (!ctx || !ctx->current || !ctx->current->layout)
20176 return 0;
20177
20178 win = ctx->current;
20179 layout = win->layout;
20180
20181 state = nk_widget(&bounds, ctx);
20182 if (!state) return 0;
20183 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20184 return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,
20185 bounds, img, text, len, align, ctx->button_behavior,
20186 style, ctx->style.font, in);
20187}
20188
20189NK_API int
20190nk_button_image_text(struct nk_context *ctx, struct nk_image img,
20191 const char *text, int len, nk_flags align)
20192{return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align);}
20193
20194
20195NK_API int nk_button_image_label(struct nk_context *ctx, struct nk_image img,
20196 const char *label, nk_flags align)
20197{return nk_button_image_text(ctx, img, label, nk_strlen(label), align);}
20198
20199NK_API int nk_button_image_label_styled(struct nk_context *ctx,
20200 const struct nk_style_button *style, struct nk_image img,
20201 const char *label, nk_flags text_alignment)
20202{return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment);}
20203
20204/*----------------------------------------------------------------
20205 *
20206 * SELECTABLE
20207 *
20208 * --------------------------------------------------------------*/
20209NK_API int
20210nk_selectable_text(struct nk_context *ctx, const char *str, int len,
20211 nk_flags align, int *value)
20212{
20213 struct nk_window *win;
20214 struct nk_panel *layout;
20215 const struct nk_input *in;
20216 const struct nk_style *style;
20217
20218 enum nk_widget_layout_states state;
20219 struct nk_rect bounds;
20220
20221 NK_ASSERT(ctx);
20222 NK_ASSERT(value);
20223 NK_ASSERT(ctx->current);
20224 NK_ASSERT(ctx->current->layout);
20225 if (!ctx || !ctx->current || !ctx->current->layout || !value)
20226 return 0;
20227
20228 win = ctx->current;
20229 layout = win->layout;
20230 style = &ctx->style;
20231
20232 state = nk_widget(&bounds, ctx);
20233 if (!state) return 0;
20234 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20235 return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds,
20236 str, len, align, value, &style->selectable, in, style->font);
20237}
20238
20239NK_API int
20240nk_selectable_image_text(struct nk_context *ctx, struct nk_image img,
20241 const char *str, int len, nk_flags align, int *value)
20242{
20243 struct nk_window *win;
20244 struct nk_panel *layout;
20245 const struct nk_input *in;
20246 const struct nk_style *style;
20247
20248 enum nk_widget_layout_states state;
20249 struct nk_rect bounds;
20250
20251 NK_ASSERT(ctx);
20252 NK_ASSERT(value);
20253 NK_ASSERT(ctx->current);
20254 NK_ASSERT(ctx->current->layout);
20255 if (!ctx || !ctx->current || !ctx->current->layout || !value)
20256 return 0;
20257
20258 win = ctx->current;
20259 layout = win->layout;
20260 style = &ctx->style;
20261
20262 state = nk_widget(&bounds, ctx);
20263 if (!state) return 0;
20264 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20265 return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds,
20266 str, len, align, value, &img, &style->selectable, in, style->font);
20267}
20268
20269NK_API int nk_select_text(struct nk_context *ctx, const char *str, int len,
20270 nk_flags align, int value)
20271{nk_selectable_text(ctx, str, len, align, &value);return value;}
20272
20273NK_API int nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, int *value)
20274{return nk_selectable_text(ctx, str, nk_strlen(str), align, value);}
20275
20276NK_API int nk_selectable_image_label(struct nk_context *ctx,struct nk_image img,
20277 const char *str, nk_flags align, int *value)
20278{return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);}
20279
20280NK_API int nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, int value)
20281{nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;}
20282
20283NK_API int nk_select_image_label(struct nk_context *ctx, struct nk_image img,
20284 const char *str, nk_flags align, int value)
20285{nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;}
20286
20287NK_API int nk_select_image_text(struct nk_context *ctx, struct nk_image img,
20288 const char *str, int len, nk_flags align, int value)
20289{nk_selectable_image_text(ctx, img, str, len, align, &value);return value;}
20290
20291/*----------------------------------------------------------------
20292 *
20293 * CHECKBOX
20294 *
20295 * --------------------------------------------------------------*/
20296NK_API int
20297nk_check_text(struct nk_context *ctx, const char *text, int len, int active)
20298{
20299 struct nk_window *win;
20300 struct nk_panel *layout;
20301 const struct nk_input *in;
20302 const struct nk_style *style;
20303
20304 struct nk_rect bounds;
20305 enum nk_widget_layout_states state;
20306
20307 NK_ASSERT(ctx);
20308 NK_ASSERT(ctx->current);
20309 NK_ASSERT(ctx->current->layout);
20310 if (!ctx || !ctx->current || !ctx->current->layout)
20311 return active;
20312
20313 win = ctx->current;
20314 style = &ctx->style;
20315 layout = win->layout;
20316
20317 state = nk_widget(&bounds, ctx);
20318 if (!state) return active;
20319 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20320 nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,
20321 text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font);
20322 return active;
20323}
20324
20325NK_API unsigned int
20326nk_check_flags_text(struct nk_context *ctx, const char *text, int len,
20327 unsigned int flags, unsigned int value)
20328{
20329 int old_active;
20330 NK_ASSERT(ctx);
20331 NK_ASSERT(text);
20332 if (!ctx || !text) return flags;
20333 old_active = (int)((flags & value) & value);
20334 if (nk_check_text(ctx, text, len, old_active))
20335 flags |= value;
20336 else flags &= ~value;
20337 return flags;
20338}
20339
20340NK_API int
20341nk_checkbox_text(struct nk_context *ctx, const char *text, int len, int *active)
20342{
20343 int old_val;
20344 NK_ASSERT(ctx);
20345 NK_ASSERT(text);
20346 NK_ASSERT(active);
20347 if (!ctx || !text || !active) return 0;
20348 old_val = *active;
20349 *active = nk_check_text(ctx, text, len, *active);
20350 return old_val != *active;
20351}
20352
20353NK_API int
20354nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len,
20355 unsigned int *flags, unsigned int value)
20356{
20357 int active;
20358 NK_ASSERT(ctx);
20359 NK_ASSERT(text);
20360 NK_ASSERT(flags);
20361 if (!ctx || !text || !flags) return 0;
20362
20363 active = (int)((*flags & value) & value);
20364 if (nk_checkbox_text(ctx, text, len, &active)) {
20365 if (active) *flags |= value;
20366 else *flags &= ~value;
20367 return 1;
20368 }
20369 return 0;
20370}
20371
20372NK_API int nk_check_label(struct nk_context *ctx, const char *label, int active)
20373{return nk_check_text(ctx, label, nk_strlen(label), active);}
20374
20375NK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label,
20376 unsigned int flags, unsigned int value)
20377{return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);}
20378
20379NK_API int nk_checkbox_label(struct nk_context *ctx, const char *label, int *active)
20380{return nk_checkbox_text(ctx, label, nk_strlen(label), active);}
20381
20382NK_API int nk_checkbox_flags_label(struct nk_context *ctx, const char *label,
20383 unsigned int *flags, unsigned int value)
20384{return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);}
20385
20386/*----------------------------------------------------------------
20387 *
20388 * OPTION
20389 *
20390 * --------------------------------------------------------------*/
20391NK_API int
20392nk_option_text(struct nk_context *ctx, const char *text, int len, int is_active)
20393{
20394 struct nk_window *win;
20395 struct nk_panel *layout;
20396 const struct nk_input *in;
20397 const struct nk_style *style;
20398
20399 struct nk_rect bounds;
20400 enum nk_widget_layout_states state;
20401
20402 NK_ASSERT(ctx);
20403 NK_ASSERT(ctx->current);
20404 NK_ASSERT(ctx->current->layout);
20405 if (!ctx || !ctx->current || !ctx->current->layout)
20406 return is_active;
20407
20408 win = ctx->current;
20409 style = &ctx->style;
20410 layout = win->layout;
20411
20412 state = nk_widget(&bounds, ctx);
20413 if (!state) return state;
20414 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20415 nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,
20416 text, len, NK_TOGGLE_OPTION, &style->option, in, style->font);
20417 return is_active;
20418}
20419
20420NK_API int
20421nk_radio_text(struct nk_context *ctx, const char *text, int len, int *active)
20422{
20423 int old_value;
20424 NK_ASSERT(ctx);
20425 NK_ASSERT(text);
20426 NK_ASSERT(active);
20427 if (!ctx || !text || !active) return 0;
20428 old_value = *active;
20429 *active = nk_option_text(ctx, text, len, old_value);
20430 return old_value != *active;
20431}
20432
20433NK_API int
20434nk_option_label(struct nk_context *ctx, const char *label, int active)
20435{return nk_option_text(ctx, label, nk_strlen(label), active);}
20436
20437NK_API int
20438nk_radio_label(struct nk_context *ctx, const char *label, int *active)
20439{return nk_radio_text(ctx, label, nk_strlen(label), active);}
20440
20441/*----------------------------------------------------------------
20442 *
20443 * SLIDER
20444 *
20445 * --------------------------------------------------------------*/
20446NK_API int
20447nk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value,
20448 float value_step)
20449{
20450 struct nk_window *win;
20451 struct nk_panel *layout;
20452 struct nk_input *in;
20453 const struct nk_style *style;
20454
20455 int ret = 0;
20456 float old_value;
20457 struct nk_rect bounds;
20458 enum nk_widget_layout_states state;
20459
20460 NK_ASSERT(ctx);
20461 NK_ASSERT(ctx->current);
20462 NK_ASSERT(ctx->current->layout);
20463 NK_ASSERT(value);
20464 if (!ctx || !ctx->current || !ctx->current->layout || !value)
20465 return ret;
20466
20467 win = ctx->current;
20468 style = &ctx->style;
20469 layout = win->layout;
20470
20471 state = nk_widget(&bounds, ctx);
20472 if (!state) return ret;
20473 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20474
20475 old_value = *value;
20476 *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value,
20477 old_value, max_value, value_step, &style->slider, in, style->font);
20478 return (old_value > *value || old_value < *value);
20479}
20480
20481NK_API float
20482nk_slide_float(struct nk_context *ctx, float min, float val, float max, float step)
20483{
20484 nk_slider_float(ctx, min, &val, max, step); return val;
20485}
20486
20487NK_API int
20488nk_slide_int(struct nk_context *ctx, int min, int val, int max, int step)
20489{
20490 float value = (float)val;
20491 nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
20492 return (int)value;
20493}
20494
20495NK_API int
20496nk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step)
20497{
20498 int ret;
20499 float value = (float)*val;
20500 ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
20501 *val = (int)value;
20502 return ret;
20503}
20504
20505/*----------------------------------------------------------------
20506 *
20507 * PROGRESSBAR
20508 *
20509 * --------------------------------------------------------------*/
20510NK_API int
20511nk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, int is_modifyable)
20512{
20513 struct nk_window *win;
20514 struct nk_panel *layout;
20515 const struct nk_style *style;
20516 const struct nk_input *in;
20517
20518 struct nk_rect bounds;
20519 enum nk_widget_layout_states state;
20520 nk_size old_value;
20521
20522 NK_ASSERT(ctx);
20523 NK_ASSERT(cur);
20524 NK_ASSERT(ctx->current);
20525 NK_ASSERT(ctx->current->layout);
20526 if (!ctx || !ctx->current || !ctx->current->layout || !cur)
20527 return 0;
20528
20529 win = ctx->current;
20530 style = &ctx->style;
20531 layout = win->layout;
20532 state = nk_widget(&bounds, ctx);
20533 if (!state) return 0;
20534
20535 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20536 old_value = *cur;
20537 *cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds,
20538 *cur, max, is_modifyable, &style->progress, in);
20539 return (*cur != old_value);
20540}
20541
20542NK_API nk_size nk_prog(struct nk_context *ctx, nk_size cur, nk_size max, int modifyable)
20543{nk_progress(ctx, &cur, max, modifyable);return cur;}
20544
20545/*----------------------------------------------------------------
20546 *
20547 * EDIT
20548 *
20549 * --------------------------------------------------------------*/
20550NK_API void
20551nk_edit_focus(struct nk_context *ctx, nk_flags flags)
20552{
20553 nk_hash hash;
20554 struct nk_window *win;
20555
20556 NK_ASSERT(ctx);
20557 NK_ASSERT(ctx->current);
20558 if (!ctx || !ctx->current) return;
20559
20560 win = ctx->current;
20561 hash = win->edit.seq;
20562 win->edit.active = nk_true;
20563 win->edit.name = hash;
20564 if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
20565 win->edit.mode = NK_TEXT_EDIT_MODE_INSERT;
20566}
20567
20568NK_API void
20569nk_edit_unfocus(struct nk_context *ctx)
20570{
20571 struct nk_window *win;
20572 NK_ASSERT(ctx);
20573 NK_ASSERT(ctx->current);
20574 if (!ctx || !ctx->current) return;
20575
20576 win = ctx->current;
20577 win->edit.active = nk_false;
20578 win->edit.name = 0;
20579}
20580
20581NK_API nk_flags
20582nk_edit_string(struct nk_context *ctx, nk_flags flags,
20583 char *memory, int *len, int max, nk_plugin_filter filter)
20584{
20585 nk_hash hash;
20586 nk_flags state;
20587 struct nk_text_edit *edit;
20588 struct nk_window *win;
20589
20590 NK_ASSERT(ctx);
20591 NK_ASSERT(memory);
20592 NK_ASSERT(len);
20593 if (!ctx || !memory || !len)
20594 return 0;
20595
20596 filter = (!filter) ? nk_filter_default: filter;
20597 win = ctx->current;
20598 hash = win->edit.seq;
20599 edit = &ctx->text_edit;
20600 nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)?
20601 NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter);
20602
20603 if (win->edit.active && hash == win->edit.name) {
20604 if (flags & NK_EDIT_NO_CURSOR)
20605 edit->cursor = nk_utf_len(memory, *len);
20606 else edit->cursor = win->edit.cursor;
20607 if (!(flags & NK_EDIT_SELECTABLE)) {
20608 edit->select_start = win->edit.cursor;
20609 edit->select_end = win->edit.cursor;
20610 } else {
20611 edit->select_start = win->edit.sel_start;
20612 edit->select_end = win->edit.sel_end;
20613 }
20614 edit->mode = win->edit.mode;
20615 edit->scrollbar.x = (float)win->edit.scrollbar.x;
20616 edit->scrollbar.y = (float)win->edit.scrollbar.y;
20617 edit->active = nk_true;
20618 } else edit->active = nk_false;
20619
20620 max = NK_MAX(1, max);
20621 *len = NK_MIN(*len, max-1);
20622 nk_str_init_fixed(&edit->string, memory, (nk_size)max);
20623 edit->string.buffer.allocated = (nk_size)*len;
20624 edit->string.len = nk_utf_len(memory, *len);
20625 state = nk_edit_buffer(ctx, flags, edit, filter);
20626 *len = (int)edit->string.buffer.allocated;
20627
20628 if (edit->active) {
20629 win->edit.cursor = edit->cursor;
20630 win->edit.sel_start = edit->select_start;
20631 win->edit.sel_end = edit->select_end;
20632 win->edit.mode = edit->mode;
20633 win->edit.scrollbar.x = (nk_ushort)edit->scrollbar.x;
20634 win->edit.scrollbar.y = (nk_ushort)edit->scrollbar.y;
20635 }
20636 return state;
20637}
20638
20639NK_API nk_flags
20640nk_edit_buffer(struct nk_context *ctx, nk_flags flags,
20641 struct nk_text_edit *edit, nk_plugin_filter filter)
20642{
20643 struct nk_window *win;
20644 struct nk_style *style;
20645 struct nk_input *in;
20646
20647 enum nk_widget_layout_states state;
20648 struct nk_rect bounds;
20649
20650 nk_flags ret_flags = 0;
20651 unsigned char prev_state;
20652 nk_hash hash;
20653
20654 /* make sure correct values */
20655 NK_ASSERT(ctx);
20656 NK_ASSERT(edit);
20657 NK_ASSERT(ctx->current);
20658 NK_ASSERT(ctx->current->layout);
20659 if (!ctx || !ctx->current || !ctx->current->layout)
20660 return 0;
20661
20662 win = ctx->current;
20663 style = &ctx->style;
20664 state = nk_widget(&bounds, ctx);
20665 if (!state) return state;
20666 in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20667
20668 /* check if edit is currently hot item */
20669 hash = win->edit.seq++;
20670 if (win->edit.active && hash == win->edit.name) {
20671 if (flags & NK_EDIT_NO_CURSOR)
20672 edit->cursor = edit->string.len;
20673 if (!(flags & NK_EDIT_SELECTABLE)) {
20674 edit->select_start = edit->cursor;
20675 edit->select_end = edit->cursor;
20676 }
20677 if (flags & NK_EDIT_CLIPBOARD)
20678 edit->clip = ctx->clip;
20679 }
20680
20681 filter = (!filter) ? nk_filter_default: filter;
20682 prev_state = (unsigned char)edit->active;
20683 in = (flags & NK_EDIT_READ_ONLY) ? 0: in;
20684 ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags,
20685 filter, edit, &style->edit, in, style->font);
20686
20687 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
20688 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT];
20689 if (edit->active && prev_state != edit->active) {
20690 /* current edit is now hot */
20691 win->edit.active = nk_true;
20692 win->edit.name = hash;
20693 } else if (prev_state && !edit->active) {
20694 /* current edit is now cold */
20695 win->edit.active = nk_false;
20696 }
20697 return ret_flags;
20698}
20699
20700NK_API nk_flags
20701nk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags,
20702 char *buffer, int max, nk_plugin_filter filter)
20703{
20704 nk_flags result;
20705 int len = nk_strlen(buffer);
20706 result = nk_edit_string(ctx, flags, buffer, &len, max, filter);
20707 buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\0';
20708 return result;
20709}
20710
20711/*----------------------------------------------------------------
20712 *
20713 * PROPERTY
20714 *
20715 * --------------------------------------------------------------*/
20716NK_INTERN struct nk_property_variant
20717nk_property_variant_int(int value, int min_value, int max_value, int step)
20718{
20719 struct nk_property_variant result;
20720 result.kind = NK_PROPERTY_INT;
20721 result.value.i = value;
20722 result.min_value.i = min_value;
20723 result.max_value.i = max_value;
20724 result.step.i = step;
20725 return result;
20726}
20727
20728NK_INTERN struct nk_property_variant
20729nk_property_variant_float(float value, float min_value, float max_value, float step)
20730{
20731 struct nk_property_variant result;
20732 result.kind = NK_PROPERTY_FLOAT;
20733 result.value.f = value;
20734 result.min_value.f = min_value;
20735 result.max_value.f = max_value;
20736 result.step.f = step;
20737 return result;
20738}
20739
20740NK_INTERN struct nk_property_variant
20741nk_property_variant_double(double value, double min_value, double max_value,
20742 double step)
20743{
20744 struct nk_property_variant result;
20745 result.kind = NK_PROPERTY_DOUBLE;
20746 result.value.d = value;
20747 result.min_value.d = min_value;
20748 result.max_value.d = max_value;
20749 result.step.d = step;
20750 return result;
20751}
20752
20753NK_INTERN void
20754nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant,
20755 float inc_per_pixel, const enum nk_property_filter filter)
20756{
20757 struct nk_window *win;
20758 struct nk_panel *layout;
20759 struct nk_input *in;
20760 const struct nk_style *style;
20761
20762 struct nk_rect bounds;
20763 enum nk_widget_layout_states s;
20764
20765 int *state = 0;
20766 nk_hash hash = 0;
20767 char *buffer = 0;
20768 int *len = 0;
20769 int *cursor = 0;
20770 int old_state;
20771
20772 char dummy_buffer[NK_MAX_NUMBER_BUFFER];
20773 int dummy_state = NK_PROPERTY_DEFAULT;
20774 int dummy_length = 0;
20775 int dummy_cursor = 0;
20776
20777 NK_ASSERT(ctx);
20778 NK_ASSERT(ctx->current);
20779 NK_ASSERT(ctx->current->layout);
20780 if (!ctx || !ctx->current || !ctx->current->layout)
20781 return;
20782
20783 win = ctx->current;
20784 layout = win->layout;
20785 style = &ctx->style;
20786 s = nk_widget(&bounds, ctx);
20787 if (!s) return;
20788 in = (s == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20789
20790 /* calculate hash from name */
20791 if (name[0] == '#') {
20792 hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++);
20793 name++; /* special number hash */
20794 } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42);
20795
20796 /* check if property is currently hot item */
20797 if (win->property.active && hash == win->property.name) {
20798 buffer = win->property.buffer;
20799 len = &win->property.length;
20800 cursor = &win->property.cursor;
20801 state = &win->property.state;
20802 } else {
20803 buffer = dummy_buffer;
20804 len = &dummy_length;
20805 cursor = &dummy_cursor;
20806 state = &dummy_state;
20807 }
20808
20809 /* execute property widget */
20810 old_state = *state;
20811 nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name,
20812 variant, inc_per_pixel, buffer, len, state, cursor,
20813 &style->property, filter, in, style->font, &ctx->text_edit);
20814
20815 if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) {
20816 /* current property is now hot */
20817 win->property.active = 1;
20818 NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len);
20819 win->property.length = *len;
20820 win->property.cursor = *cursor;
20821 win->property.state = *state;
20822 win->property.name = hash;
20823 if (*state == NK_PROPERTY_DRAG) {
20824 ctx->input.mouse.grab = nk_true;
20825 ctx->input.mouse.grabbed = nk_true;
20826 }
20827 }
20828
20829 /* check if previously active property is now inactive */
20830 if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) {
20831 if (old_state == NK_PROPERTY_DRAG) {
20832 ctx->input.mouse.grab = nk_false;
20833 ctx->input.mouse.grabbed = nk_false;
20834 ctx->input.mouse.ungrab = nk_true;
20835 }
20836 win->property.active = 0;
20837 }
20838}
20839
20840NK_API void
20841nk_property_int(struct nk_context *ctx, const char *name,
20842 int min, int *val, int max, int step, float inc_per_pixel)
20843{
20844 struct nk_property_variant variant;
20845 NK_ASSERT(ctx);
20846 NK_ASSERT(name);
20847 NK_ASSERT(val);
20848
20849 if (!ctx || !ctx->current || !name || !val) return;
20850 variant = nk_property_variant_int(*val, min, max, step);
20851 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
20852 *val = variant.value.i;
20853}
20854
20855NK_API void
20856nk_property_float(struct nk_context *ctx, const char *name,
20857 float min, float *val, float max, float step, float inc_per_pixel)
20858{
20859 struct nk_property_variant variant;
20860 NK_ASSERT(ctx);
20861 NK_ASSERT(name);
20862 NK_ASSERT(val);
20863
20864 if (!ctx || !ctx->current || !name || !val) return;
20865 variant = nk_property_variant_float(*val, min, max, step);
20866 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
20867 *val = variant.value.f;
20868}
20869
20870NK_API void
20871nk_property_double(struct nk_context *ctx, const char *name,
20872 double min, double *val, double max, double step, float inc_per_pixel)
20873{
20874 struct nk_property_variant variant;
20875 NK_ASSERT(ctx);
20876 NK_ASSERT(name);
20877 NK_ASSERT(val);
20878
20879 if (!ctx || !ctx->current || !name || !val) return;
20880 variant = nk_property_variant_double(*val, min, max, step);
20881 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
20882 *val = variant.value.d;
20883}
20884
20885NK_API int
20886nk_propertyi(struct nk_context *ctx, const char *name, int min, int val,
20887 int max, int step, float inc_per_pixel)
20888{
20889 struct nk_property_variant variant;
20890 NK_ASSERT(ctx);
20891 NK_ASSERT(name);
20892
20893 if (!ctx || !ctx->current || !name) return val;
20894 variant = nk_property_variant_int(val, min, max, step);
20895 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
20896 val = variant.value.i;
20897 return val;
20898}
20899
20900NK_API float
20901nk_propertyf(struct nk_context *ctx, const char *name, float min,
20902 float val, float max, float step, float inc_per_pixel)
20903{
20904 struct nk_property_variant variant;
20905 NK_ASSERT(ctx);
20906 NK_ASSERT(name);
20907
20908 if (!ctx || !ctx->current || !name) return val;
20909 variant = nk_property_variant_float(val, min, max, step);
20910 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
20911 val = variant.value.f;
20912 return val;
20913}
20914
20915NK_API double
20916nk_propertyd(struct nk_context *ctx, const char *name, double min,
20917 double val, double max, double step, float inc_per_pixel)
20918{
20919 struct nk_property_variant variant;
20920 NK_ASSERT(ctx);
20921 NK_ASSERT(name);
20922
20923 if (!ctx || !ctx->current || !name) return val;
20924 variant = nk_property_variant_double(val, min, max, step);
20925 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
20926 val = variant.value.d;
20927 return val;
20928}
20929
20930/*----------------------------------------------------------------
20931 *
20932 * COLOR PICKER
20933 *
20934 * --------------------------------------------------------------*/
20935NK_API int
20936nk_color_pick(struct nk_context * ctx, struct nk_color *color,
20937 enum nk_color_format fmt)
20938{
20939 struct nk_window *win;
20940 struct nk_panel *layout;
20941 const struct nk_style *config;
20942 const struct nk_input *in;
20943
20944 enum nk_widget_layout_states state;
20945 struct nk_rect bounds;
20946
20947 NK_ASSERT(ctx);
20948 NK_ASSERT(color);
20949 NK_ASSERT(ctx->current);
20950 NK_ASSERT(ctx->current->layout);
20951 if (!ctx || !ctx->current || !ctx->current->layout || !color)
20952 return 0;
20953
20954 win = ctx->current;
20955 config = &ctx->style;
20956 layout = win->layout;
20957 state = nk_widget(&bounds, ctx);
20958 if (!state) return 0;
20959 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20960 return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds,
20961 nk_vec2(0,0), in, config->font);
20962}
20963
20964NK_API struct nk_color
20965nk_color_picker(struct nk_context *ctx, struct nk_color color,
20966 enum nk_color_format fmt)
20967{
20968 nk_color_pick(ctx, &color, fmt);
20969 return color;
20970}
20971
20972/* -------------------------------------------------------------
20973 *
20974 * CHART
20975 *
20976 * --------------------------------------------------------------*/
20977NK_API int
20978nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type,
20979 struct nk_color color, struct nk_color highlight,
20980 int count, float min_value, float max_value)
20981{
20982 struct nk_window *win;
20983 struct nk_chart *chart;
20984 const struct nk_style *config;
20985 const struct nk_style_chart *style;
20986
20987 const struct nk_style_item *background;
20988 struct nk_rect bounds = {0, 0, 0, 0};
20989
20990 NK_ASSERT(ctx);
20991 NK_ASSERT(ctx->current);
20992 NK_ASSERT(ctx->current->layout);
20993
20994 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
20995 if (!nk_widget(&bounds, ctx)) {
20996 chart = &ctx->current->layout->chart;
20997 nk_zero(chart, sizeof(*chart));
20998 return 0;
20999 }
21000
21001 win = ctx->current;
21002 config = &ctx->style;
21003 chart = &win->layout->chart;
21004 style = &config->chart;
21005
21006 /* setup basic generic chart */
21007 nk_zero(chart, sizeof(*chart));
21008 chart->x = bounds.x + style->padding.x;
21009 chart->y = bounds.y + style->padding.y;
21010 chart->w = bounds.w - 2 * style->padding.x;
21011 chart->h = bounds.h - 2 * style->padding.y;
21012 chart->w = NK_MAX(chart->w, 2 * style->padding.x);
21013 chart->h = NK_MAX(chart->h, 2 * style->padding.y);
21014
21015 /* add first slot into chart */
21016 {struct nk_chart_slot *slot = &chart->slots[chart->slot++];
21017 slot->type = type;
21018 slot->count = count;
21019 slot->color = color;
21020 slot->highlight = highlight;
21021 slot->min = NK_MIN(min_value, max_value);
21022 slot->max = NK_MAX(min_value, max_value);
21023 slot->range = slot->max - slot->min;}
21024
21025 /* draw chart background */
21026 background = &style->background;
21027 if (background->type == NK_STYLE_ITEM_IMAGE) {
21028 nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white);
21029 } else {
21030 nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color);
21031 nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),
21032 style->rounding, style->background.data.color);
21033 }
21034 return 1;
21035}
21036
21037NK_API int
21038nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type,
21039 int count, float min_value, float max_value)
21040{return nk_chart_begin_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);}
21041
21042NK_API void
21043nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type,
21044 struct nk_color color, struct nk_color highlight,
21045 int count, float min_value, float max_value)
21046{
21047 NK_ASSERT(ctx);
21048 NK_ASSERT(ctx->current);
21049 NK_ASSERT(ctx->current->layout);
21050 NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT);
21051 if (!ctx || !ctx->current || !ctx->current->layout) return;
21052 if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return;
21053
21054 /* add another slot into the graph */
21055 {struct nk_chart *chart = &ctx->current->layout->chart;
21056 struct nk_chart_slot *slot = &chart->slots[chart->slot++];
21057 slot->type = type;
21058 slot->count = count;
21059 slot->color = color;
21060 slot->highlight = highlight;
21061 slot->min = NK_MIN(min_value, max_value);
21062 slot->max = NK_MAX(min_value, max_value);
21063 slot->range = slot->max - slot->min;}
21064}
21065
21066NK_API void
21067nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type,
21068 int count, float min_value, float max_value)
21069{nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);}
21070
21071NK_INTERN nk_flags
21072nk_chart_push_line(struct nk_context *ctx, struct nk_window *win,
21073 struct nk_chart *g, float value, int slot)
21074{
21075 struct nk_panel *layout = win->layout;
21076 const struct nk_input *i = &ctx->input;
21077 struct nk_command_buffer *out = &win->buffer;
21078
21079 nk_flags ret = 0;
21080 struct nk_vec2 cur;
21081 struct nk_rect bounds;
21082 struct nk_color color;
21083 float step;
21084 float range;
21085 float ratio;
21086
21087 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
21088 step = g->w / (float)g->slots[slot].count;
21089 range = g->slots[slot].max - g->slots[slot].min;
21090 ratio = (value - g->slots[slot].min) / range;
21091
21092 if (g->slots[slot].index == 0) {
21093 /* first data point does not have a connection */
21094 g->slots[slot].last.x = g->x;
21095 g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h;
21096
21097 bounds.x = g->slots[slot].last.x - 2;
21098 bounds.y = g->slots[slot].last.y - 2;
21099 bounds.w = bounds.h = 4;
21100
21101 color = g->slots[slot].color;
21102 if (!(layout->flags & NK_WINDOW_ROM) &&
21103 NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){
21104 ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0;
21105 ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down &&
21106 i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
21107 color = g->slots[slot].highlight;
21108 }
21109 nk_fill_rect(out, bounds, 0, color);
21110 g->slots[slot].index += 1;
21111 return ret;
21112 }
21113
21114 /* draw a line between the last data point and the new one */
21115 color = g->slots[slot].color;
21116 cur.x = g->x + (float)(step * (float)g->slots[slot].index);
21117 cur.y = (g->y + g->h) - (ratio * (float)g->h);
21118 nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color);
21119
21120 bounds.x = cur.x - 3;
21121 bounds.y = cur.y - 3;
21122 bounds.w = bounds.h = 6;
21123
21124 /* user selection of current data point */
21125 if (!(layout->flags & NK_WINDOW_ROM)) {
21126 if (nk_input_is_mouse_hovering_rect(i, bounds)) {
21127 ret = NK_CHART_HOVERING;
21128 ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down &&
21129 i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
21130 color = g->slots[slot].highlight;
21131 }
21132 }
21133 nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color);
21134
21135 /* save current data point position */
21136 g->slots[slot].last.x = cur.x;
21137 g->slots[slot].last.y = cur.y;
21138 g->slots[slot].index += 1;
21139 return ret;
21140}
21141
21142NK_INTERN nk_flags
21143nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win,
21144 struct nk_chart *chart, float value, int slot)
21145{
21146 struct nk_command_buffer *out = &win->buffer;
21147 const struct nk_input *in = &ctx->input;
21148 struct nk_panel *layout = win->layout;
21149
21150 float ratio;
21151 nk_flags ret = 0;
21152 struct nk_color color;
21153 struct nk_rect item = {0,0,0,0};
21154
21155 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
21156 if (chart->slots[slot].index >= chart->slots[slot].count)
21157 return nk_false;
21158 if (chart->slots[slot].count) {
21159 float padding = (float)(chart->slots[slot].count-1);
21160 item.w = (chart->w - padding) / (float)(chart->slots[slot].count);
21161 }
21162
21163 /* calculate bounds of current bar chart entry */
21164 color = chart->slots[slot].color;;
21165 item.h = chart->h * NK_ABS((value/chart->slots[slot].range));
21166 if (value >= 0) {
21167 ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range);
21168 item.y = (chart->y + chart->h) - chart->h * ratio;
21169 } else {
21170 ratio = (value - chart->slots[slot].max) / chart->slots[slot].range;
21171 item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h;
21172 }
21173 item.x = chart->x + ((float)chart->slots[slot].index * item.w);
21174 item.x = item.x + ((float)chart->slots[slot].index);
21175
21176 /* user chart bar selection */
21177 if (!(layout->flags & NK_WINDOW_ROM) &&
21178 NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) {
21179 ret = NK_CHART_HOVERING;
21180 ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down &&
21181 in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
21182 color = chart->slots[slot].highlight;
21183 }
21184 nk_fill_rect(out, item, 0, color);
21185 chart->slots[slot].index += 1;
21186 return ret;
21187}
21188
21189NK_API nk_flags
21190nk_chart_push_slot(struct nk_context *ctx, float value, int slot)
21191{
21192 nk_flags flags;
21193 struct nk_window *win;
21194
21195 NK_ASSERT(ctx);
21196 NK_ASSERT(ctx->current);
21197 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
21198 NK_ASSERT(slot < ctx->current->layout->chart.slot);
21199 if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false;
21200 if (slot >= ctx->current->layout->chart.slot) return nk_false;
21201
21202 win = ctx->current;
21203 if (win->layout->chart.slot < slot) return nk_false;
21204 switch (win->layout->chart.slots[slot].type) {
21205 case NK_CHART_LINES:
21206 flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break;
21207 case NK_CHART_COLUMN:
21208 flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break;
21209 default:
21210 case NK_CHART_MAX:
21211 flags = 0;
21212 }
21213 return flags;
21214}
21215
21216NK_API nk_flags
21217nk_chart_push(struct nk_context *ctx, float value)
21218{return nk_chart_push_slot(ctx, value, 0);}
21219
21220NK_API void
21221nk_chart_end(struct nk_context *ctx)
21222{
21223 struct nk_window *win;
21224 struct nk_chart *chart;
21225
21226 NK_ASSERT(ctx);
21227 NK_ASSERT(ctx->current);
21228 if (!ctx || !ctx->current)
21229 return;
21230
21231 win = ctx->current;
21232 chart = &win->layout->chart;
21233 NK_MEMSET(chart, 0, sizeof(*chart));
21234 return;
21235}
21236
21237NK_API void
21238nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values,
21239 int count, int offset)
21240{
21241 int i = 0;
21242 float min_value;
21243 float max_value;
21244
21245 NK_ASSERT(ctx);
21246 NK_ASSERT(values);
21247 if (!ctx || !values || !count) return;
21248
21249 min_value = values[offset];
21250 max_value = values[offset];
21251 for (i = 0; i < count; ++i) {
21252 min_value = NK_MIN(values[i + offset], min_value);
21253 max_value = NK_MAX(values[i + offset], max_value);
21254 }
21255 nk_chart_begin(ctx, type, count, min_value, max_value);
21256 for (i = 0; i < count; ++i)
21257 nk_chart_push(ctx, values[i + offset]);
21258 nk_chart_end(ctx);
21259}
21260
21261NK_API void
21262nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata,
21263 float(*value_getter)(void* user, int index), int count, int offset)
21264{
21265 int i = 0;
21266 float min_value;
21267 float max_value;
21268
21269 NK_ASSERT(ctx);
21270 NK_ASSERT(value_getter);
21271 if (!ctx || !value_getter || !count) return;
21272
21273 max_value = min_value = value_getter(userdata, offset);
21274 for (i = 0; i < count; ++i) {
21275 float value = value_getter(userdata, i + offset);
21276 min_value = NK_MIN(value, min_value);
21277 max_value = NK_MAX(value, max_value);
21278 }
21279 nk_chart_begin(ctx, type, count, min_value, max_value);
21280 for (i = 0; i < count; ++i)
21281 nk_chart_push(ctx, value_getter(userdata, i + offset));
21282 nk_chart_end(ctx);
21283}
21284
21285/* -------------------------------------------------------------
21286 *
21287 * GROUP
21288 *
21289 * --------------------------------------------------------------*/
21290NK_API int
21291nk_group_scrolled_offset_begin(struct nk_context *ctx,
21292 nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags)
21293{
21294 struct nk_rect bounds;
21295 struct nk_window panel;
21296 struct nk_window *win;
21297
21298 win = ctx->current;
21299 nk_panel_alloc_space(&bounds, ctx);
21300 {const struct nk_rect *c = &win->layout->clip;
21301 if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) &&
21302 !(flags & NK_WINDOW_MOVABLE)) {
21303 return 0;
21304 }}
21305 if (win->flags & NK_WINDOW_ROM)
21306 flags |= NK_WINDOW_ROM;
21307
21308 /* initialize a fake window to create the panel from */
21309 nk_zero(&panel, sizeof(panel));
21310 panel.bounds = bounds;
21311 panel.flags = flags;
21312 panel.scrollbar.x = *x_offset;
21313 panel.scrollbar.y = *y_offset;
21314 panel.buffer = win->buffer;
21315 panel.layout = (struct nk_panel*)nk_create_panel(ctx);
21316 ctx->current = &panel;
21317 nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP);
21318
21319 win->buffer = panel.buffer;
21320 win->buffer.clip = panel.layout->clip;
21321 panel.layout->offset_x = x_offset;
21322 panel.layout->offset_y = y_offset;
21323 panel.layout->parent = win->layout;
21324 win->layout = panel.layout;
21325
21326 ctx->current = win;
21327 if ((panel.layout->flags & NK_WINDOW_CLOSED) ||
21328 (panel.layout->flags & NK_WINDOW_MINIMIZED))
21329 {
21330 nk_flags f = panel.layout->flags;
21331 nk_group_scrolled_end(ctx);
21332 if (f & NK_WINDOW_CLOSED)
21333 return NK_WINDOW_CLOSED;
21334 if (f & NK_WINDOW_MINIMIZED)
21335 return NK_WINDOW_MINIMIZED;
21336 }
21337 return 1;
21338}
21339
21340NK_API void
21341nk_group_scrolled_end(struct nk_context *ctx)
21342{
21343 struct nk_window *win;
21344 struct nk_panel *parent;
21345 struct nk_panel *g;
21346
21347 struct nk_rect clip;
21348 struct nk_window pan;
21349 struct nk_vec2 panel_padding;
21350
21351 NK_ASSERT(ctx);
21352 NK_ASSERT(ctx->current);
21353 if (!ctx || !ctx->current)
21354 return;
21355
21356 /* make sure nk_group_begin was called correctly */
21357 NK_ASSERT(ctx->current);
21358 win = ctx->current;
21359 NK_ASSERT(win->layout);
21360 g = win->layout;
21361 NK_ASSERT(g->parent);
21362 parent = g->parent;
21363
21364 /* dummy window */
21365 nk_zero_struct(pan);
21366 panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP);
21367 pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h);
21368 pan.bounds.x = g->bounds.x - panel_padding.x;
21369 pan.bounds.w = g->bounds.w + 2 * panel_padding.x;
21370 pan.bounds.h = g->bounds.h + g->header_height + g->menu.h;
21371 if (g->flags & NK_WINDOW_BORDER) {
21372 pan.bounds.x -= g->border;
21373 pan.bounds.y -= g->border;
21374 pan.bounds.w += 2*g->border;
21375 pan.bounds.h += 2*g->border;
21376 }
21377 if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) {
21378 pan.bounds.w += ctx->style.window.scrollbar_size.x;
21379 pan.bounds.h += ctx->style.window.scrollbar_size.y;
21380 }
21381 pan.scrollbar.x = *g->offset_x;
21382 pan.scrollbar.y = *g->offset_y;
21383 pan.flags = g->flags;
21384 pan.buffer = win->buffer;
21385 pan.layout = g;
21386 pan.parent = win;
21387 ctx->current = &pan;
21388
21389 /* make sure group has correct clipping rectangle */
21390 nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y,
21391 pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x);
21392 nk_push_scissor(&pan.buffer, clip);
21393 nk_end(ctx);
21394
21395 win->buffer = pan.buffer;
21396 nk_push_scissor(&win->buffer, parent->clip);
21397 ctx->current = win;
21398 win->layout = parent;
21399 g->bounds = pan.bounds;
21400 return;
21401}
21402
21403NK_API int
21404nk_group_scrolled_begin(struct nk_context *ctx,
21405 struct nk_scroll *scroll, const char *title, nk_flags flags)
21406{return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags);}
21407
21408NK_API int
21409nk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags)
21410{
21411 int title_len;
21412 nk_hash title_hash;
21413 struct nk_window *win;
21414 nk_uint *x_offset;
21415 nk_uint *y_offset;
21416
21417 NK_ASSERT(ctx);
21418 NK_ASSERT(title);
21419 NK_ASSERT(ctx->current);
21420 NK_ASSERT(ctx->current->layout);
21421 if (!ctx || !ctx->current || !ctx->current->layout || !title)
21422 return 0;
21423
21424 /* find persistent group scrollbar value */
21425 win = ctx->current;
21426 title_len = (int)nk_strlen(title);
21427 title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP);
21428 x_offset = nk_find_value(win, title_hash);
21429 if (!x_offset) {
21430 x_offset = nk_add_value(ctx, win, title_hash, 0);
21431 y_offset = nk_add_value(ctx, win, title_hash+1, 0);
21432
21433 NK_ASSERT(x_offset);
21434 NK_ASSERT(y_offset);
21435 if (!x_offset || !y_offset) return 0;
21436 *x_offset = *y_offset = 0;
21437 } else y_offset = nk_find_value(win, title_hash+1);
21438 return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);
21439}
21440
21441NK_API void
21442nk_group_end(struct nk_context *ctx)
21443{nk_group_scrolled_end(ctx);}
21444
21445NK_API int
21446nk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view,
21447 const char *title, nk_flags flags, int row_height, int row_count)
21448{
21449 int title_len;
21450 nk_hash title_hash;
21451 nk_uint *x_offset;
21452 nk_uint *y_offset;
21453
21454 int result;
21455 struct nk_window *win;
21456 struct nk_panel *layout;
21457 const struct nk_style *style;
21458 struct nk_vec2 item_spacing;
21459
21460 NK_ASSERT(ctx);
21461 NK_ASSERT(view);
21462 NK_ASSERT(title);
21463 if (!ctx || !view || !title) return 0;
21464
21465 win = ctx->current;
21466 style = &ctx->style;
21467 item_spacing = style->window.spacing;
21468 row_height += NK_MAX(0, (int)item_spacing.y);
21469
21470 /* find persistent list view scrollbar offset */
21471 title_len = (int)nk_strlen(title);
21472 title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP);
21473 x_offset = nk_find_value(win, title_hash);
21474 if (!x_offset) {
21475 x_offset = nk_add_value(ctx, win, title_hash, 0);
21476 y_offset = nk_add_value(ctx, win, title_hash+1, 0);
21477
21478 NK_ASSERT(x_offset);
21479 NK_ASSERT(y_offset);
21480 if (!x_offset || !y_offset) return 0;
21481 *x_offset = *y_offset = 0;
21482 } else y_offset = nk_find_value(win, title_hash+1);
21483 view->scroll_value = *y_offset;
21484 view->scroll_pointer = y_offset;
21485
21486 *y_offset = 0;
21487 result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);
21488 win = ctx->current;
21489 layout = win->layout;
21490
21491 view->total_height = row_height * NK_MAX(row_count,1);
21492 view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f);
21493 view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height), 0);
21494 view->end = view->begin + view->count;
21495 view->ctx = ctx;
21496 return result;
21497}
21498
21499NK_API void
21500nk_list_view_end(struct nk_list_view *view)
21501{
21502 struct nk_context *ctx;
21503 struct nk_window *win;
21504 struct nk_panel *layout;
21505
21506 NK_ASSERT(view);
21507 NK_ASSERT(view->ctx);
21508 NK_ASSERT(view->scroll_pointer);
21509 if (!view || !view->ctx) return;
21510
21511 ctx = view->ctx;
21512 win = ctx->current;
21513 layout = win->layout;
21514 layout->at_y = layout->bounds.y + (float)view->total_height;
21515 *view->scroll_pointer = *view->scroll_pointer + view->scroll_value;
21516 nk_group_end(view->ctx);
21517}
21518
21519/* --------------------------------------------------------------
21520 *
21521 * POPUP
21522 *
21523 * --------------------------------------------------------------*/
21524NK_API int
21525nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type,
21526 const char *title, nk_flags flags, struct nk_rect rect)
21527{
21528 struct nk_window *popup;
21529 struct nk_window *win;
21530 struct nk_panel *panel;
21531
21532 int title_len;
21533 nk_hash title_hash;
21534 nk_size allocated;
21535
21536 NK_ASSERT(ctx);
21537 NK_ASSERT(title);
21538 NK_ASSERT(ctx->current);
21539 NK_ASSERT(ctx->current->layout);
21540 if (!ctx || !ctx->current || !ctx->current->layout)
21541 return 0;
21542
21543 win = ctx->current;
21544 panel = win->layout;
21545 NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP) && "popups are not allowed to have popups");
21546 (void)panel;
21547 title_len = (int)nk_strlen(title);
21548 title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP);
21549
21550 popup = win->popup.win;
21551 if (!popup) {
21552 popup = (struct nk_window*)nk_create_window(ctx);
21553 popup->parent = win;
21554 win->popup.win = popup;
21555 win->popup.active = 0;
21556 win->popup.type = NK_PANEL_POPUP;
21557 }
21558
21559 /* make sure we have to correct popup */
21560 if (win->popup.name != title_hash) {
21561 if (!win->popup.active) {
21562 nk_zero(popup, sizeof(*popup));
21563 win->popup.name = title_hash;
21564 win->popup.active = 1;
21565 win->popup.type = NK_PANEL_POPUP;
21566 } else return 0;
21567 }
21568
21569 /* popup position is local to window */
21570 ctx->current = popup;
21571 rect.x += win->layout->clip.x;
21572 rect.y += win->layout->clip.y;
21573
21574 /* setup popup data */
21575 popup->parent = win;
21576 popup->bounds = rect;
21577 popup->seq = ctx->seq;
21578 popup->layout = (struct nk_panel*)nk_create_panel(ctx);
21579 popup->flags = flags;
21580 popup->flags |= NK_WINDOW_BORDER;
21581 if (type == NK_POPUP_DYNAMIC)
21582 popup->flags |= NK_WINDOW_DYNAMIC;
21583
21584 popup->buffer = win->buffer;
21585 nk_start_popup(ctx, win);
21586 allocated = ctx->memory.allocated;
21587 nk_push_scissor(&popup->buffer, nk_null_rect);
21588
21589 if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) {
21590 /* popup is running therefore invalidate parent panels */
21591 struct nk_panel *root;
21592 root = win->layout;
21593 while (root) {
21594 root->flags |= NK_WINDOW_ROM;
21595 root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;
21596 root = root->parent;
21597 }
21598 win->popup.active = 1;
21599 popup->layout->offset_x = &popup->scrollbar.x;
21600 popup->layout->offset_y = &popup->scrollbar.y;
21601 popup->layout->parent = win->layout;
21602 return 1;
21603 } else {
21604 /* popup was closed/is invalid so cleanup */
21605 struct nk_panel *root;
21606 root = win->layout;
21607 while (root) {
21608 root->flags |= NK_WINDOW_REMOVE_ROM;
21609 root = root->parent;
21610 }
21611 win->popup.buf.active = 0;
21612 win->popup.active = 0;
21613 ctx->memory.allocated = allocated;
21614 ctx->current = win;
21615 nk_free_panel(ctx, popup->layout);
21616 popup->layout = 0;
21617 return 0;
21618 }
21619}
21620
21621NK_INTERN int
21622nk_nonblock_begin(struct nk_context *ctx,
21623 nk_flags flags, struct nk_rect body, struct nk_rect header,
21624 enum nk_panel_type panel_type)
21625{
21626 struct nk_window *popup;
21627 struct nk_window *win;
21628 struct nk_panel *panel;
21629 int is_active = nk_true;
21630
21631 NK_ASSERT(ctx);
21632 NK_ASSERT(ctx->current);
21633 NK_ASSERT(ctx->current->layout);
21634 if (!ctx || !ctx->current || !ctx->current->layout)
21635 return 0;
21636
21637 /* popups cannot have popups */
21638 win = ctx->current;
21639 panel = win->layout;
21640 NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP));
21641 (void)panel;
21642 popup = win->popup.win;
21643 if (!popup) {
21644 /* create window for nonblocking popup */
21645 popup = (struct nk_window*)nk_create_window(ctx);
21646 popup->parent = win;
21647 win->popup.win = popup;
21648 win->popup.type = panel_type;
21649 nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON);
21650 } else {
21651 /* close the popup if user pressed outside or in the header */
21652 int pressed, in_body, in_header;
21653 pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
21654 in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);
21655 in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header);
21656 if (pressed && (!in_body || in_header))
21657 is_active = nk_false;
21658 }
21659 win->popup.header = header;
21660
21661 if (!is_active) {
21662 /* remove read only mode from all parent panels */
21663 struct nk_panel *root = win->layout;
21664 while (root) {
21665 root->flags |= NK_WINDOW_REMOVE_ROM;
21666 root = root->parent;
21667 }
21668 return is_active;
21669 }
21670
21671 popup->bounds = body;
21672 popup->parent = win;
21673 popup->layout = (struct nk_panel*)nk_create_panel(ctx);
21674 popup->flags = flags;
21675 popup->flags |= NK_WINDOW_BORDER;
21676 popup->flags |= NK_WINDOW_DYNAMIC;
21677 popup->seq = ctx->seq;
21678 win->popup.active = 1;
21679 NK_ASSERT(popup->layout);
21680
21681 nk_start_popup(ctx, win);
21682 popup->buffer = win->buffer;
21683 nk_push_scissor(&popup->buffer, nk_null_rect);
21684 ctx->current = popup;
21685
21686 nk_panel_begin(ctx, 0, panel_type);
21687 win->buffer = popup->buffer;
21688 popup->layout->parent = win->layout;
21689 popup->layout->offset_x = &popup->scrollbar.x;
21690 popup->layout->offset_y = &popup->scrollbar.y;
21691
21692 /* set read only mode to all parent panels */
21693 {struct nk_panel *root;
21694 root = win->layout;
21695 while (root) {
21696 root->flags |= NK_WINDOW_ROM;
21697 root = root->parent;
21698 }}
21699 return is_active;
21700}
21701
21702NK_API void
21703nk_popup_close(struct nk_context *ctx)
21704{
21705 struct nk_window *popup;
21706 NK_ASSERT(ctx);
21707 if (!ctx || !ctx->current) return;
21708
21709 popup = ctx->current;
21710 NK_ASSERT(popup->parent);
21711 NK_ASSERT(popup->layout->type & NK_PANEL_SET_POPUP);
21712 popup->flags |= NK_WINDOW_HIDDEN;
21713}
21714
21715NK_API void
21716nk_popup_end(struct nk_context *ctx)
21717{
21718 struct nk_window *win;
21719 struct nk_window *popup;
21720
21721 NK_ASSERT(ctx);
21722 NK_ASSERT(ctx->current);
21723 NK_ASSERT(ctx->current->layout);
21724 if (!ctx || !ctx->current || !ctx->current->layout)
21725 return;
21726
21727 popup = ctx->current;
21728 if (!popup->parent) return;
21729 win = popup->parent;
21730 if (popup->flags & NK_WINDOW_HIDDEN) {
21731 struct nk_panel *root;
21732 root = win->layout;
21733 while (root) {
21734 root->flags |= NK_WINDOW_REMOVE_ROM;
21735 root = root->parent;
21736 }
21737 win->popup.active = 0;
21738 }
21739 nk_push_scissor(&popup->buffer, nk_null_rect);
21740 nk_end(ctx);
21741
21742 win->buffer = popup->buffer;
21743 nk_finish_popup(ctx, win);
21744 ctx->current = win;
21745 nk_push_scissor(&win->buffer, win->layout->clip);
21746}
21747/* -------------------------------------------------------------
21748 *
21749 * TOOLTIP
21750 *
21751 * -------------------------------------------------------------- */
21752NK_API int
21753nk_tooltip_begin(struct nk_context *ctx, float width)
21754{
21755 struct nk_window *win;
21756 const struct nk_input *in;
21757 struct nk_rect bounds;
21758 int ret;
21759
21760 NK_ASSERT(ctx);
21761 NK_ASSERT(ctx->current);
21762 NK_ASSERT(ctx->current->layout);
21763 if (!ctx || !ctx->current || !ctx->current->layout)
21764 return 0;
21765
21766 /* make sure that no nonblocking popup is currently active */
21767 win = ctx->current;
21768 in = &ctx->input;
21769 if (win->popup.win && (win->popup.type & NK_PANEL_SET_NONBLOCK))
21770 return 0;
21771
21772 bounds.w = width;
21773 bounds.h = nk_null_rect.h;
21774 bounds.x = (in->mouse.pos.x + 1) - win->layout->clip.x;
21775 bounds.y = (in->mouse.pos.y + 1) - win->layout->clip.y;
21776
21777 ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC,
21778 "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds);
21779 if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM;
21780 win->popup.type = NK_PANEL_TOOLTIP;
21781 ctx->current->layout->type = NK_PANEL_TOOLTIP;
21782 return ret;
21783}
21784
21785NK_API void
21786nk_tooltip_end(struct nk_context *ctx)
21787{
21788 NK_ASSERT(ctx);
21789 NK_ASSERT(ctx->current);
21790 if (!ctx || !ctx->current) return;
21791 ctx->current->seq--;
21792 nk_popup_close(ctx);
21793 nk_popup_end(ctx);
21794}
21795
21796NK_API void
21797nk_tooltip(struct nk_context *ctx, const char *text)
21798{
21799 const struct nk_style *style;
21800 struct nk_vec2 padding;
21801
21802 int text_len;
21803 float text_width;
21804 float text_height;
21805
21806 NK_ASSERT(ctx);
21807 NK_ASSERT(ctx->current);
21808 NK_ASSERT(ctx->current->layout);
21809 NK_ASSERT(text);
21810 if (!ctx || !ctx->current || !ctx->current->layout || !text)
21811 return;
21812
21813 /* fetch configuration data */
21814 style = &ctx->style;
21815 padding = style->window.padding;
21816
21817 /* calculate size of the text and tooltip */
21818 text_len = nk_strlen(text);
21819 text_width = style->font->width(style->font->userdata,
21820 style->font->height, text, text_len);
21821 text_width += (4 * padding.x);
21822 text_height = (style->font->height + 2 * padding.y);
21823
21824 /* execute tooltip and fill with text */
21825 if (nk_tooltip_begin(ctx, (float)text_width)) {
21826 nk_layout_row_dynamic(ctx, (float)text_height, 1);
21827 nk_text(ctx, text, text_len, NK_TEXT_LEFT);
21828 nk_tooltip_end(ctx);
21829 }
21830}
21831/* -------------------------------------------------------------
21832 *
21833 * CONTEXTUAL
21834 *
21835 * -------------------------------------------------------------- */
21836NK_API int
21837nk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size,
21838 struct nk_rect trigger_bounds)
21839{
21840 struct nk_window *win;
21841 struct nk_window *popup;
21842 struct nk_rect body;
21843
21844 NK_STORAGE const struct nk_rect null_rect = {0,0,0,0};
21845 int is_clicked = 0;
21846 int is_active = 0;
21847 int is_open = 0;
21848 int ret = 0;
21849
21850 NK_ASSERT(ctx);
21851 NK_ASSERT(ctx->current);
21852 NK_ASSERT(ctx->current->layout);
21853 if (!ctx || !ctx->current || !ctx->current->layout)
21854 return 0;
21855
21856 win = ctx->current;
21857 ++win->popup.con_count;
21858
21859 /* check if currently active contextual is active */
21860 popup = win->popup.win;
21861 is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL);
21862 is_clicked = nk_input_mouse_clicked(&ctx->input, NK_BUTTON_RIGHT, trigger_bounds);
21863 if (win->popup.active_con && win->popup.con_count != win->popup.active_con)
21864 return 0;
21865 if ((is_clicked && is_open && !is_active) || (!is_open && !is_active && !is_clicked))
21866 return 0;
21867
21868 /* calculate contextual position on click */
21869 win->popup.active_con = win->popup.con_count;
21870 if (is_clicked) {
21871 body.x = ctx->input.mouse.pos.x;
21872 body.y = ctx->input.mouse.pos.y;
21873 } else {
21874 body.x = popup->bounds.x;
21875 body.y = popup->bounds.y;
21876 }
21877 body.w = size.x;
21878 body.h = size.y;
21879
21880 /* start nonblocking contextual popup */
21881 ret = nk_nonblock_begin(ctx, flags|NK_WINDOW_NO_SCROLLBAR, body,
21882 null_rect, NK_PANEL_CONTEXTUAL);
21883 if (ret) win->popup.type = NK_PANEL_CONTEXTUAL;
21884 else {
21885 win->popup.active_con = 0;
21886 if (win->popup.win)
21887 win->popup.win->flags = 0;
21888 }
21889 return ret;
21890}
21891
21892NK_API int
21893nk_contextual_item_text(struct nk_context *ctx, const char *text, int len,
21894 nk_flags alignment)
21895{
21896 struct nk_window *win;
21897 const struct nk_input *in;
21898 const struct nk_style *style;
21899
21900 struct nk_rect bounds;
21901 enum nk_widget_layout_states state;
21902
21903 NK_ASSERT(ctx);
21904 NK_ASSERT(ctx->current);
21905 NK_ASSERT(ctx->current->layout);
21906 if (!ctx || !ctx->current || !ctx->current->layout)
21907 return 0;
21908
21909 win = ctx->current;
21910 style = &ctx->style;
21911 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
21912 if (!state) return nk_false;
21913
21914 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21915 if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,
21916 text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) {
21917 nk_contextual_close(ctx);
21918 return nk_true;
21919 }
21920 return nk_false;
21921}
21922
21923NK_API int nk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align)
21924{return nk_contextual_item_text(ctx, label, nk_strlen(label), align);}
21925
21926NK_API int
21927nk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img,
21928 const char *text, int len, nk_flags align)
21929{
21930 struct nk_window *win;
21931 const struct nk_input *in;
21932 const struct nk_style *style;
21933
21934 struct nk_rect bounds;
21935 enum nk_widget_layout_states state;
21936
21937 NK_ASSERT(ctx);
21938 NK_ASSERT(ctx->current);
21939 NK_ASSERT(ctx->current->layout);
21940 if (!ctx || !ctx->current || !ctx->current->layout)
21941 return 0;
21942
21943 win = ctx->current;
21944 style = &ctx->style;
21945 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
21946 if (!state) return nk_false;
21947
21948 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21949 if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds,
21950 img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){
21951 nk_contextual_close(ctx);
21952 return nk_true;
21953 }
21954 return nk_false;
21955}
21956
21957NK_API int nk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img,
21958 const char *label, nk_flags align)
21959{return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);}
21960
21961NK_API int
21962nk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,
21963 const char *text, int len, nk_flags align)
21964{
21965 struct nk_window *win;
21966 const struct nk_input *in;
21967 const struct nk_style *style;
21968
21969 struct nk_rect bounds;
21970 enum nk_widget_layout_states state;
21971
21972 NK_ASSERT(ctx);
21973 NK_ASSERT(ctx->current);
21974 NK_ASSERT(ctx->current->layout);
21975 if (!ctx || !ctx->current || !ctx->current->layout)
21976 return 0;
21977
21978 win = ctx->current;
21979 style = &ctx->style;
21980 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
21981 if (!state) return nk_false;
21982
21983 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21984 if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,
21985 symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) {
21986 nk_contextual_close(ctx);
21987 return nk_true;
21988 }
21989 return nk_false;
21990}
21991
21992NK_API int nk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,
21993 const char *text, nk_flags align)
21994{return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);}
21995
21996NK_API void
21997nk_contextual_close(struct nk_context *ctx)
21998{
21999 NK_ASSERT(ctx);
22000 NK_ASSERT(ctx->current);
22001 NK_ASSERT(ctx->current->layout);
22002 if (!ctx || !ctx->current || !ctx->current->layout) return;
22003 nk_popup_close(ctx);
22004}
22005
22006NK_API void
22007nk_contextual_end(struct nk_context *ctx)
22008{
22009 struct nk_window *popup;
22010 struct nk_panel *panel;
22011 NK_ASSERT(ctx);
22012 NK_ASSERT(ctx->current);
22013 if (!ctx || !ctx->current) return;
22014
22015 popup = ctx->current;
22016 panel = popup->layout;
22017 NK_ASSERT(popup->parent);
22018 NK_ASSERT(panel->type & NK_PANEL_SET_POPUP);
22019 if (panel->flags & NK_WINDOW_DYNAMIC) {
22020 /* Close behavior
22021 This is a bit hack solution since we do not now before we end our popup
22022 how big it will be. We therefore do not directly know when a
22023 click outside the non-blocking popup must close it at that direct frame.
22024 Instead it will be closed in the next frame.*/
22025 struct nk_rect body = {0,0,0,0};
22026 if (panel->at_y < (panel->bounds.y + panel->bounds.h)) {
22027 struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type);
22028 body = panel->bounds;
22029 body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height);
22030 body.h = (panel->bounds.y + panel->bounds.h) - body.y;
22031 }
22032
22033 {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
22034 int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);
22035 if (pressed && in_body)
22036 popup->flags |= NK_WINDOW_HIDDEN;
22037 }
22038 }
22039 if (popup->flags & NK_WINDOW_HIDDEN)
22040 popup->seq = 0;
22041 nk_popup_end(ctx);
22042 return;
22043}
22044/* -------------------------------------------------------------
22045 *
22046 * COMBO
22047 *
22048 * --------------------------------------------------------------*/
22049NK_INTERN int
22050nk_combo_begin(struct nk_context *ctx, struct nk_window *win,
22051 struct nk_vec2 size, int is_clicked, struct nk_rect header)
22052{
22053 struct nk_window *popup;
22054 int is_open = 0;
22055 int is_active = 0;
22056 struct nk_rect body;
22057 nk_hash hash;
22058
22059 NK_ASSERT(ctx);
22060 NK_ASSERT(ctx->current);
22061 NK_ASSERT(ctx->current->layout);
22062 if (!ctx || !ctx->current || !ctx->current->layout)
22063 return 0;
22064
22065 popup = win->popup.win;
22066 body.x = header.x;
22067 body.w = size.x;
22068 body.y = header.y + header.h-ctx->style.window.combo_border;
22069 body.h = size.y;
22070
22071 hash = win->popup.combo_count++;
22072 is_open = (popup) ? nk_true:nk_false;
22073 is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO);
22074 if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||
22075 (!is_open && !is_active && !is_clicked)) return 0;
22076 if (!nk_nonblock_begin(ctx, 0, body,
22077 (is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0;
22078
22079 win->popup.type = NK_PANEL_COMBO;
22080 win->popup.name = hash;
22081 return 1;
22082}
22083
22084NK_API int
22085nk_combo_begin_text(struct nk_context *ctx, const char *selected, int len,
22086 struct nk_vec2 size)
22087{
22088 const struct nk_input *in;
22089 struct nk_window *win;
22090 struct nk_style *style;
22091
22092 enum nk_widget_layout_states s;
22093 int is_clicked = nk_false;
22094 struct nk_rect header;
22095 const struct nk_style_item *background;
22096 struct nk_text text;
22097
22098 NK_ASSERT(ctx);
22099 NK_ASSERT(selected);
22100 NK_ASSERT(ctx->current);
22101 NK_ASSERT(ctx->current->layout);
22102 if (!ctx || !ctx->current || !ctx->current->layout || !selected)
22103 return 0;
22104
22105 win = ctx->current;
22106 style = &ctx->style;
22107 s = nk_widget(&header, ctx);
22108 if (s == NK_WIDGET_INVALID)
22109 return 0;
22110
22111 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
22112 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
22113 is_clicked = nk_true;
22114
22115 /* draw combo box header background and border */
22116 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
22117 background = &style->combo.active;
22118 text.text = style->combo.label_active;
22119 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
22120 background = &style->combo.hover;
22121 text.text = style->combo.label_hover;
22122 } else {
22123 background = &style->combo.normal;
22124 text.text = style->combo.label_normal;
22125 }
22126 if (background->type == NK_STYLE_ITEM_IMAGE) {
22127 text.background = nk_rgba(0,0,0,0);
22128 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
22129 } else {
22130 text.background = background->data.color;
22131 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
22132 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
22133 }
22134 {
22135 /* print currently selected text item */
22136 struct nk_rect label;
22137 struct nk_rect button;
22138 struct nk_rect content;
22139
22140 enum nk_symbol_type sym;
22141 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22142 sym = style->combo.sym_hover;
22143 else if (is_clicked)
22144 sym = style->combo.sym_active;
22145 else sym = style->combo.sym_normal;
22146
22147 /* calculate button */
22148 button.w = header.h - 2 * style->combo.button_padding.y;
22149 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
22150 button.y = header.y + style->combo.button_padding.y;
22151 button.h = button.w;
22152
22153 content.x = button.x + style->combo.button.padding.x;
22154 content.y = button.y + style->combo.button.padding.y;
22155 content.w = button.w - 2 * style->combo.button.padding.x;
22156 content.h = button.h - 2 * style->combo.button.padding.y;
22157
22158 /* draw selected label */
22159 text.padding = nk_vec2(0,0);
22160 label.x = header.x + style->combo.content_padding.x;
22161 label.y = header.y + style->combo.content_padding.y;
22162 label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;;
22163 label.h = header.h - 2 * style->combo.content_padding.y;
22164 nk_widget_text(&win->buffer, label, selected, len, &text,
22165 NK_TEXT_LEFT, ctx->style.font);
22166
22167 /* draw open/close button */
22168 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
22169 &ctx->style.combo.button, sym, style->font);
22170 }
22171 return nk_combo_begin(ctx, win, size, is_clicked, header);
22172}
22173
22174NK_API int nk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size)
22175{return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size);}
22176
22177NK_API int
22178nk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size)
22179{
22180 struct nk_window *win;
22181 struct nk_style *style;
22182 const struct nk_input *in;
22183
22184 struct nk_rect header;
22185 int is_clicked = nk_false;
22186 enum nk_widget_layout_states s;
22187 const struct nk_style_item *background;
22188
22189 NK_ASSERT(ctx);
22190 NK_ASSERT(ctx->current);
22191 NK_ASSERT(ctx->current->layout);
22192 if (!ctx || !ctx->current || !ctx->current->layout)
22193 return 0;
22194
22195 win = ctx->current;
22196 style = &ctx->style;
22197 s = nk_widget(&header, ctx);
22198 if (s == NK_WIDGET_INVALID)
22199 return 0;
22200
22201 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
22202 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
22203 is_clicked = nk_true;
22204
22205 /* draw combo box header background and border */
22206 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)
22207 background = &style->combo.active;
22208 else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22209 background = &style->combo.hover;
22210 else background = &style->combo.normal;
22211
22212 if (background->type == NK_STYLE_ITEM_IMAGE) {
22213 nk_draw_image(&win->buffer, header, &background->data.image,nk_white);
22214 } else {
22215 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
22216 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
22217 }
22218 {
22219 struct nk_rect content;
22220 struct nk_rect button;
22221 struct nk_rect bounds;
22222
22223 enum nk_symbol_type sym;
22224 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22225 sym = style->combo.sym_hover;
22226 else if (is_clicked)
22227 sym = style->combo.sym_active;
22228 else sym = style->combo.sym_normal;
22229
22230 /* calculate button */
22231 button.w = header.h - 2 * style->combo.button_padding.y;
22232 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
22233 button.y = header.y + style->combo.button_padding.y;
22234 button.h = button.w;
22235
22236 content.x = button.x + style->combo.button.padding.x;
22237 content.y = button.y + style->combo.button.padding.y;
22238 content.w = button.w - 2 * style->combo.button.padding.x;
22239 content.h = button.h - 2 * style->combo.button.padding.y;
22240
22241 /* draw color */
22242 bounds.h = header.h - 4 * style->combo.content_padding.y;
22243 bounds.y = header.y + 2 * style->combo.content_padding.y;
22244 bounds.x = header.x + 2 * style->combo.content_padding.x;
22245 bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x;
22246 nk_fill_rect(&win->buffer, bounds, 0, color);
22247
22248 /* draw open/close button */
22249 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
22250 &ctx->style.combo.button, sym, style->font);
22251 }
22252 return nk_combo_begin(ctx, win, size, is_clicked, header);
22253}
22254
22255NK_API int
22256nk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size)
22257{
22258 struct nk_window *win;
22259 struct nk_style *style;
22260 const struct nk_input *in;
22261
22262 struct nk_rect header;
22263 int is_clicked = nk_false;
22264 enum nk_widget_layout_states s;
22265 const struct nk_style_item *background;
22266 struct nk_color sym_background;
22267 struct nk_color symbol_color;
22268
22269 NK_ASSERT(ctx);
22270 NK_ASSERT(ctx->current);
22271 NK_ASSERT(ctx->current->layout);
22272 if (!ctx || !ctx->current || !ctx->current->layout)
22273 return 0;
22274
22275 win = ctx->current;
22276 style = &ctx->style;
22277 s = nk_widget(&header, ctx);
22278 if (s == NK_WIDGET_INVALID)
22279 return 0;
22280
22281 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
22282 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
22283 is_clicked = nk_true;
22284
22285 /* draw combo box header background and border */
22286 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
22287 background = &style->combo.active;
22288 symbol_color = style->combo.symbol_active;
22289 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
22290 background = &style->combo.hover;
22291 symbol_color = style->combo.symbol_hover;
22292 } else {
22293 background = &style->combo.normal;
22294 symbol_color = style->combo.symbol_hover;
22295 }
22296
22297 if (background->type == NK_STYLE_ITEM_IMAGE) {
22298 sym_background = nk_rgba(0,0,0,0);
22299 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
22300 } else {
22301 sym_background = background->data.color;
22302 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
22303 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
22304 }
22305 {
22306 struct nk_rect bounds = {0,0,0,0};
22307 struct nk_rect content;
22308 struct nk_rect button;
22309
22310 enum nk_symbol_type sym;
22311 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22312 sym = style->combo.sym_hover;
22313 else if (is_clicked)
22314 sym = style->combo.sym_active;
22315 else sym = style->combo.sym_normal;
22316
22317 /* calculate button */
22318 button.w = header.h - 2 * style->combo.button_padding.y;
22319 button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;
22320 button.y = header.y + style->combo.button_padding.y;
22321 button.h = button.w;
22322
22323 content.x = button.x + style->combo.button.padding.x;
22324 content.y = button.y + style->combo.button.padding.y;
22325 content.w = button.w - 2 * style->combo.button.padding.x;
22326 content.h = button.h - 2 * style->combo.button.padding.y;
22327
22328 /* draw symbol */
22329 bounds.h = header.h - 2 * style->combo.content_padding.y;
22330 bounds.y = header.y + style->combo.content_padding.y;
22331 bounds.x = header.x + style->combo.content_padding.x;
22332 bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;
22333 nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color,
22334 1.0f, style->font);
22335
22336 /* draw open/close button */
22337 nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,
22338 &ctx->style.combo.button, sym, style->font);
22339 }
22340 return nk_combo_begin(ctx, win, size, is_clicked, header);
22341}
22342
22343NK_API int
22344nk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len,
22345 enum nk_symbol_type symbol, struct nk_vec2 size)
22346{
22347 struct nk_window *win;
22348 struct nk_style *style;
22349 struct nk_input *in;
22350
22351 struct nk_rect header;
22352 int is_clicked = nk_false;
22353 enum nk_widget_layout_states s;
22354 const struct nk_style_item *background;
22355 struct nk_color symbol_color;
22356 struct nk_text text;
22357
22358 NK_ASSERT(ctx);
22359 NK_ASSERT(ctx->current);
22360 NK_ASSERT(ctx->current->layout);
22361 if (!ctx || !ctx->current || !ctx->current->layout)
22362 return 0;
22363
22364 win = ctx->current;
22365 style = &ctx->style;
22366 s = nk_widget(&header, ctx);
22367 if (!s) return 0;
22368
22369 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
22370 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
22371 is_clicked = nk_true;
22372
22373 /* draw combo box header background and border */
22374 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
22375 background = &style->combo.active;
22376 symbol_color = style->combo.symbol_active;
22377 text.text = style->combo.label_active;
22378 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
22379 background = &style->combo.hover;
22380 symbol_color = style->combo.symbol_hover;
22381 text.text = style->combo.label_hover;
22382 } else {
22383 background = &style->combo.normal;
22384 symbol_color = style->combo.symbol_normal;
22385 text.text = style->combo.label_normal;
22386 }
22387 if (background->type == NK_STYLE_ITEM_IMAGE) {
22388 text.background = nk_rgba(0,0,0,0);
22389 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
22390 } else {
22391 text.background = background->data.color;
22392 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
22393 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
22394 }
22395 {
22396 struct nk_rect content;
22397 struct nk_rect button;
22398 struct nk_rect label;
22399 struct nk_rect image;
22400
22401 enum nk_symbol_type sym;
22402 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22403 sym = style->combo.sym_hover;
22404 else if (is_clicked)
22405 sym = style->combo.sym_active;
22406 else sym = style->combo.sym_normal;
22407
22408 /* calculate button */
22409 button.w = header.h - 2 * style->combo.button_padding.y;
22410 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
22411 button.y = header.y + style->combo.button_padding.y;
22412 button.h = button.w;
22413
22414 content.x = button.x + style->combo.button.padding.x;
22415 content.y = button.y + style->combo.button.padding.y;
22416 content.w = button.w - 2 * style->combo.button.padding.x;
22417 content.h = button.h - 2 * style->combo.button.padding.y;
22418 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
22419 &ctx->style.combo.button, sym, style->font);
22420
22421 /* draw symbol */
22422 image.x = header.x + style->combo.content_padding.x;
22423 image.y = header.y + style->combo.content_padding.y;
22424 image.h = header.h - 2 * style->combo.content_padding.y;
22425 image.w = image.h;
22426 nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color,
22427 1.0f, style->font);
22428
22429 /* draw label */
22430 text.padding = nk_vec2(0,0);
22431 label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;
22432 label.y = header.y + style->combo.content_padding.y;
22433 label.w = (button.x - style->combo.content_padding.x) - label.x;
22434 label.h = header.h - 2 * style->combo.content_padding.y;
22435 nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);
22436 }
22437 return nk_combo_begin(ctx, win, size, is_clicked, header);
22438}
22439
22440NK_API int
22441nk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size)
22442{
22443 struct nk_window *win;
22444 struct nk_style *style;
22445 const struct nk_input *in;
22446
22447 struct nk_rect header;
22448 int is_clicked = nk_false;
22449 enum nk_widget_layout_states s;
22450 const struct nk_style_item *background;
22451
22452 NK_ASSERT(ctx);
22453 NK_ASSERT(ctx->current);
22454 NK_ASSERT(ctx->current->layout);
22455 if (!ctx || !ctx->current || !ctx->current->layout)
22456 return 0;
22457
22458 win = ctx->current;
22459 style = &ctx->style;
22460 s = nk_widget(&header, ctx);
22461 if (s == NK_WIDGET_INVALID)
22462 return 0;
22463
22464 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
22465 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
22466 is_clicked = nk_true;
22467
22468 /* draw combo box header background and border */
22469 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)
22470 background = &style->combo.active;
22471 else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22472 background = &style->combo.hover;
22473 else background = &style->combo.normal;
22474
22475 if (background->type == NK_STYLE_ITEM_IMAGE) {
22476 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
22477 } else {
22478 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
22479 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
22480 }
22481 {
22482 struct nk_rect bounds = {0,0,0,0};
22483 struct nk_rect content;
22484 struct nk_rect button;
22485
22486 enum nk_symbol_type sym;
22487 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22488 sym = style->combo.sym_hover;
22489 else if (is_clicked)
22490 sym = style->combo.sym_active;
22491 else sym = style->combo.sym_normal;
22492
22493 /* calculate button */
22494 button.w = header.h - 2 * style->combo.button_padding.y;
22495 button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;
22496 button.y = header.y + style->combo.button_padding.y;
22497 button.h = button.w;
22498
22499 content.x = button.x + style->combo.button.padding.x;
22500 content.y = button.y + style->combo.button.padding.y;
22501 content.w = button.w - 2 * style->combo.button.padding.x;
22502 content.h = button.h - 2 * style->combo.button.padding.y;
22503
22504 /* draw image */
22505 bounds.h = header.h - 2 * style->combo.content_padding.y;
22506 bounds.y = header.y + style->combo.content_padding.y;
22507 bounds.x = header.x + style->combo.content_padding.x;
22508 bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;
22509 nk_draw_image(&win->buffer, bounds, &img, nk_white);
22510
22511 /* draw open/close button */
22512 nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,
22513 &ctx->style.combo.button, sym, style->font);
22514 }
22515 return nk_combo_begin(ctx, win, size, is_clicked, header);
22516}
22517
22518NK_API int
22519nk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len,
22520 struct nk_image img, struct nk_vec2 size)
22521{
22522 struct nk_window *win;
22523 struct nk_style *style;
22524 struct nk_input *in;
22525
22526 struct nk_rect header;
22527 int is_clicked = nk_false;
22528 enum nk_widget_layout_states s;
22529 const struct nk_style_item *background;
22530 struct nk_text text;
22531
22532 NK_ASSERT(ctx);
22533 NK_ASSERT(ctx->current);
22534 NK_ASSERT(ctx->current->layout);
22535 if (!ctx || !ctx->current || !ctx->current->layout)
22536 return 0;
22537
22538 win = ctx->current;
22539 style = &ctx->style;
22540 s = nk_widget(&header, ctx);
22541 if (!s) return 0;
22542
22543 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
22544 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
22545 is_clicked = nk_true;
22546
22547 /* draw combo box header background and border */
22548 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
22549 background = &style->combo.active;
22550 text.text = style->combo.label_active;
22551 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
22552 background = &style->combo.hover;
22553 text.text = style->combo.label_hover;
22554 } else {
22555 background = &style->combo.normal;
22556 text.text = style->combo.label_normal;
22557 }
22558 if (background->type == NK_STYLE_ITEM_IMAGE) {
22559 text.background = nk_rgba(0,0,0,0);
22560 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
22561 } else {
22562 text.background = background->data.color;
22563 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
22564 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
22565 }
22566 {
22567 struct nk_rect content;
22568 struct nk_rect button;
22569 struct nk_rect label;
22570 struct nk_rect image;
22571
22572 enum nk_symbol_type sym;
22573 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22574 sym = style->combo.sym_hover;
22575 else if (is_clicked)
22576 sym = style->combo.sym_active;
22577 else sym = style->combo.sym_normal;
22578
22579 /* calculate button */
22580 button.w = header.h - 2 * style->combo.button_padding.y;
22581 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
22582 button.y = header.y + style->combo.button_padding.y;
22583 button.h = button.w;
22584
22585 content.x = button.x + style->combo.button.padding.x;
22586 content.y = button.y + style->combo.button.padding.y;
22587 content.w = button.w - 2 * style->combo.button.padding.x;
22588 content.h = button.h - 2 * style->combo.button.padding.y;
22589 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
22590 &ctx->style.combo.button, sym, style->font);
22591
22592 /* draw image */
22593 image.x = header.x + style->combo.content_padding.x;
22594 image.y = header.y + style->combo.content_padding.y;
22595 image.h = header.h - 2 * style->combo.content_padding.y;
22596 image.w = image.h;
22597 nk_draw_image(&win->buffer, image, &img, nk_white);
22598
22599 /* draw label */
22600 text.padding = nk_vec2(0,0);
22601 label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;
22602 label.y = header.y + style->combo.content_padding.y;
22603 label.w = (button.x - style->combo.content_padding.x) - label.x;
22604 label.h = header.h - 2 * style->combo.content_padding.y;
22605 nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);
22606 }
22607 return nk_combo_begin(ctx, win, size, is_clicked, header);
22608}
22609
22610NK_API int nk_combo_begin_symbol_label(struct nk_context *ctx,
22611 const char *selected, enum nk_symbol_type type, struct nk_vec2 size)
22612{return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size);}
22613
22614NK_API int nk_combo_begin_image_label(struct nk_context *ctx,
22615 const char *selected, struct nk_image img, struct nk_vec2 size)
22616{return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size);}
22617
22618NK_API int nk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align)
22619{return nk_contextual_item_text(ctx, text, len, align);}
22620
22621NK_API int nk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align)
22622{return nk_contextual_item_label(ctx, label, align);}
22623
22624NK_API int nk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text,
22625 int len, nk_flags alignment)
22626{return nk_contextual_item_image_text(ctx, img, text, len, alignment);}
22627
22628NK_API int nk_combo_item_image_label(struct nk_context *ctx, struct nk_image img,
22629 const char *text, nk_flags alignment)
22630{return nk_contextual_item_image_label(ctx, img, text, alignment);}
22631
22632NK_API int nk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
22633 const char *text, int len, nk_flags alignment)
22634{return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment);}
22635
22636NK_API int nk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
22637 const char *label, nk_flags alignment)
22638{return nk_contextual_item_symbol_label(ctx, sym, label, alignment);}
22639
22640NK_API void nk_combo_end(struct nk_context *ctx)
22641{nk_contextual_end(ctx);}
22642
22643NK_API void nk_combo_close(struct nk_context *ctx)
22644{nk_contextual_close(ctx);}
22645
22646NK_API int
22647nk_combo(struct nk_context *ctx, const char **items, int count,
22648 int selected, int item_height, struct nk_vec2 size)
22649{
22650 int i = 0;
22651 int max_height;
22652 struct nk_vec2 item_spacing;
22653 struct nk_vec2 window_padding;
22654
22655 NK_ASSERT(ctx);
22656 NK_ASSERT(items);
22657 NK_ASSERT(ctx->current);
22658 if (!ctx || !items ||!count)
22659 return selected;
22660
22661 item_spacing = ctx->style.window.spacing;
22662 window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
22663 max_height = count * item_height + count * (int)item_spacing.y;
22664 max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
22665 size.y = NK_MIN(size.y, (float)max_height);
22666 if (nk_combo_begin_label(ctx, items[selected], size)) {
22667 nk_layout_row_dynamic(ctx, (float)item_height, 1);
22668 for (i = 0; i < count; ++i) {
22669 if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
22670 selected = i;
22671 }
22672 nk_combo_end(ctx);
22673 }
22674 return selected;
22675}
22676
22677NK_API int
22678nk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator,
22679 int separator, int selected, int count, int item_height, struct nk_vec2 size)
22680{
22681 int i;
22682 int max_height;
22683 struct nk_vec2 item_spacing;
22684 struct nk_vec2 window_padding;
22685 const char *current_item;
22686 const char *iter;
22687 int length = 0;
22688
22689 NK_ASSERT(ctx);
22690 NK_ASSERT(items_separated_by_separator);
22691 if (!ctx || !items_separated_by_separator)
22692 return selected;
22693
22694 /* calculate popup window */
22695 item_spacing = ctx->style.window.spacing;
22696 window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
22697 max_height = count * item_height + count * (int)item_spacing.y;
22698 max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
22699 size.y = NK_MIN(size.y, (float)max_height);
22700
22701 /* find selected item */
22702 current_item = items_separated_by_separator;
22703 for (i = 0; i < count; ++i) {
22704 iter = current_item;
22705 while (*iter && *iter != separator) iter++;
22706 length = (int)(iter - current_item);
22707 if (i == selected) break;
22708 current_item = iter + 1;
22709 }
22710
22711 if (nk_combo_begin_text(ctx, current_item, length, size)) {
22712 current_item = items_separated_by_separator;
22713 nk_layout_row_dynamic(ctx, (float)item_height, 1);
22714 for (i = 0; i < count; ++i) {
22715 iter = current_item;
22716 while (*iter && *iter != separator) iter++;
22717 length = (int)(iter - current_item);
22718 if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT))
22719 selected = i;
22720 current_item = current_item + length + 1;
22721 }
22722 nk_combo_end(ctx);
22723 }
22724 return selected;
22725}
22726
22727NK_API int
22728nk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros,
22729 int selected, int count, int item_height, struct nk_vec2 size)
22730{return nk_combo_separator(ctx, items_separated_by_zeros, '\0', selected, count, item_height, size);}
22731
22732NK_API int
22733nk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**),
22734 void *userdata, int selected, int count, int item_height, struct nk_vec2 size)
22735{
22736 int i;
22737 int max_height;
22738 struct nk_vec2 item_spacing;
22739 struct nk_vec2 window_padding;
22740 const char *item;
22741
22742 NK_ASSERT(ctx);
22743 NK_ASSERT(item_getter);
22744 if (!ctx || !item_getter)
22745 return selected;
22746
22747 /* calculate popup window */
22748 item_spacing = ctx->style.window.spacing;
22749 window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
22750 max_height = count * item_height + count * (int)item_spacing.y;
22751 max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
22752 size.y = NK_MIN(size.y, (float)max_height);
22753
22754 item_getter(userdata, selected, &item);
22755 if (nk_combo_begin_label(ctx, item, size)) {
22756 nk_layout_row_dynamic(ctx, (float)item_height, 1);
22757 for (i = 0; i < count; ++i) {
22758 item_getter(userdata, i, &item);
22759 if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT))
22760 selected = i;
22761 }
22762 nk_combo_end(ctx);
22763 }
22764 return selected;
22765}
22766
22767NK_API void nk_combobox(struct nk_context *ctx, const char **items, int count,
22768 int *selected, int item_height, struct nk_vec2 size)
22769{*selected = nk_combo(ctx, items, count, *selected, item_height, size);}
22770
22771NK_API void nk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros,
22772 int *selected, int count, int item_height, struct nk_vec2 size)
22773{*selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size);}
22774
22775NK_API void nk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator,
22776 int separator,int *selected, int count, int item_height, struct nk_vec2 size)
22777{*selected = nk_combo_separator(ctx, items_separated_by_separator, separator,
22778 *selected, count, item_height, size);}
22779
22780NK_API void nk_combobox_callback(struct nk_context *ctx,
22781 void(*item_getter)(void* data, int id, const char **out_text),
22782 void *userdata, int *selected, int count, int item_height, struct nk_vec2 size)
22783{*selected = nk_combo_callback(ctx, item_getter, userdata, *selected, count, item_height, size);}
22784
22785/*
22786 * -------------------------------------------------------------
22787 *
22788 * MENU
22789 *
22790 * --------------------------------------------------------------
22791 */
22792NK_INTERN int
22793nk_menu_begin(struct nk_context *ctx, struct nk_window *win,
22794 const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size)
22795{
22796 int is_open = 0;
22797 int is_active = 0;
22798 struct nk_rect body;
22799 struct nk_window *popup;
22800 nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU);
22801
22802 NK_ASSERT(ctx);
22803 NK_ASSERT(ctx->current);
22804 NK_ASSERT(ctx->current->layout);
22805 if (!ctx || !ctx->current || !ctx->current->layout)
22806 return 0;
22807
22808 body.x = header.x;
22809 body.w = size.x;
22810 body.y = header.y + header.h;
22811 body.h = size.y;
22812
22813 popup = win->popup.win;
22814 is_open = popup ? nk_true : nk_false;
22815 is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU);
22816 if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||
22817 (!is_open && !is_active && !is_clicked)) return 0;
22818 if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU))
22819 return 0;
22820
22821 win->popup.type = NK_PANEL_MENU;
22822 win->popup.name = hash;
22823 return 1;
22824}
22825
22826NK_API int
22827nk_menu_begin_text(struct nk_context *ctx, const char *title, int len,
22828 nk_flags align, struct nk_vec2 size)
22829{
22830 struct nk_window *win;
22831 const struct nk_input *in;
22832 struct nk_rect header;
22833 int is_clicked = nk_false;
22834 nk_flags state;
22835
22836 NK_ASSERT(ctx);
22837 NK_ASSERT(ctx->current);
22838 NK_ASSERT(ctx->current->layout);
22839 if (!ctx || !ctx->current || !ctx->current->layout)
22840 return 0;
22841
22842 win = ctx->current;
22843 state = nk_widget(&header, ctx);
22844 if (!state) return 0;
22845 in = (state == NK_WIDGET_ROM || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
22846 if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header,
22847 title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))
22848 is_clicked = nk_true;
22849 return nk_menu_begin(ctx, win, title, is_clicked, header, size);
22850}
22851
22852NK_API int nk_menu_begin_label(struct nk_context *ctx,
22853 const char *text, nk_flags align, struct nk_vec2 size)
22854{return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size);}
22855
22856NK_API int
22857nk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img,
22858 struct nk_vec2 size)
22859{
22860 struct nk_window *win;
22861 struct nk_rect header;
22862 const struct nk_input *in;
22863 int is_clicked = nk_false;
22864 nk_flags state;
22865
22866 NK_ASSERT(ctx);
22867 NK_ASSERT(ctx->current);
22868 NK_ASSERT(ctx->current->layout);
22869 if (!ctx || !ctx->current || !ctx->current->layout)
22870 return 0;
22871
22872 win = ctx->current;
22873 state = nk_widget(&header, ctx);
22874 if (!state) return 0;
22875 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
22876 if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header,
22877 img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in))
22878 is_clicked = nk_true;
22879 return nk_menu_begin(ctx, win, id, is_clicked, header, size);
22880}
22881
22882NK_API int
22883nk_menu_begin_symbol(struct nk_context *ctx, const char *id,
22884 enum nk_symbol_type sym, struct nk_vec2 size)
22885{
22886 struct nk_window *win;
22887 const struct nk_input *in;
22888 struct nk_rect header;
22889 int is_clicked = nk_false;
22890 nk_flags state;
22891
22892 NK_ASSERT(ctx);
22893 NK_ASSERT(ctx->current);
22894 NK_ASSERT(ctx->current->layout);
22895 if (!ctx || !ctx->current || !ctx->current->layout)
22896 return 0;
22897
22898 win = ctx->current;
22899 state = nk_widget(&header, ctx);
22900 if (!state) return 0;
22901 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
22902 if (nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, header,
22903 sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))
22904 is_clicked = nk_true;
22905 return nk_menu_begin(ctx, win, id, is_clicked, header, size);
22906}
22907
22908NK_API int
22909nk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len,
22910 nk_flags align, struct nk_image img, struct nk_vec2 size)
22911{
22912 struct nk_window *win;
22913 struct nk_rect header;
22914 const struct nk_input *in;
22915 int is_clicked = nk_false;
22916 nk_flags state;
22917
22918 NK_ASSERT(ctx);
22919 NK_ASSERT(ctx->current);
22920 NK_ASSERT(ctx->current->layout);
22921 if (!ctx || !ctx->current || !ctx->current->layout)
22922 return 0;
22923
22924 win = ctx->current;
22925 state = nk_widget(&header, ctx);
22926 if (!state) return 0;
22927 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
22928 if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,
22929 header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,
22930 ctx->style.font, in))
22931 is_clicked = nk_true;
22932 return nk_menu_begin(ctx, win, title, is_clicked, header, size);
22933}
22934
22935NK_API int nk_menu_begin_image_label(struct nk_context *ctx,
22936 const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size)
22937{return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size);}
22938
22939NK_API int
22940nk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len,
22941 nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size)
22942{
22943 struct nk_window *win;
22944 struct nk_rect header;
22945 const struct nk_input *in;
22946 int is_clicked = nk_false;
22947 nk_flags state;
22948
22949 NK_ASSERT(ctx);
22950 NK_ASSERT(ctx->current);
22951 NK_ASSERT(ctx->current->layout);
22952 if (!ctx || !ctx->current || !ctx->current->layout)
22953 return 0;
22954
22955 win = ctx->current;
22956 state = nk_widget(&header, ctx);
22957 if (!state) return 0;
22958
22959 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
22960 if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer,
22961 header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,
22962 ctx->style.font, in)) is_clicked = nk_true;
22963 return nk_menu_begin(ctx, win, title, is_clicked, header, size);
22964}
22965
22966NK_API int nk_menu_begin_symbol_label(struct nk_context *ctx,
22967 const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size )
22968{return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size);}
22969
22970NK_API int nk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align)
22971{return nk_contextual_item_text(ctx, title, len, align);}
22972
22973NK_API int nk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align)
22974{return nk_contextual_item_label(ctx, label, align);}
22975
22976NK_API int nk_menu_item_image_label(struct nk_context *ctx, struct nk_image img,
22977 const char *label, nk_flags align)
22978{return nk_contextual_item_image_label(ctx, img, label, align);}
22979
22980NK_API int nk_menu_item_image_text(struct nk_context *ctx, struct nk_image img,
22981 const char *text, int len, nk_flags align)
22982{return nk_contextual_item_image_text(ctx, img, text, len, align);}
22983
22984NK_API int nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
22985 const char *text, int len, nk_flags align)
22986{return nk_contextual_item_symbol_text(ctx, sym, text, len, align);}
22987
22988NK_API int nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
22989 const char *label, nk_flags align)
22990{return nk_contextual_item_symbol_label(ctx, sym, label, align);}
22991
22992NK_API void nk_menu_close(struct nk_context *ctx)
22993{nk_contextual_close(ctx);}
22994
22995NK_API void
22996nk_menu_end(struct nk_context *ctx)
22997{nk_contextual_end(ctx);}
22998
22999#endif
23000